Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@conqa/serverless-openapi-documentation

Package Overview
Dependencies
Maintainers
10
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@conqa/serverless-openapi-documentation - npm Package Compare versions

Comparing version 1.0.4 to 1.1.0

package-lock.json

40

CHANGELOG.md

@@ -8,5 +8,41 @@ # Changelog

## [Unreleased]
[Unreleased]: https://github.com/conqa/serverless-openapi-documentation/compare/v1.0.4...HEAD
## [1.1.0] - 2019-05-09
### Added
- Support for securitySchemes and security #15
- Support for servers #18
- Support for schemas included by path with all $refs merged into components #7
### Changed
- Convert project from Yarn to npm #5
- Switch to eslint #8
- Update Readme #19
## [1.0.4] - 2019-05-07
### Fixed
- Fix issue with last release where the package was published from the root directory, not the build directory
## [1.0.3] - 2019-05-07
### Fixed
- Fix for requestBody and parameters #6
## [1.0.2] - 2019-05-03
### Changed
- test tag publish
## [1.0.1] - 2019-05-02
### Changed
- test tag publish
## [1.0.0] - 2019-05-02
### Changed
- inital release after forking from temando/serverless-openapi-documentation
[Unreleased]: https://github.com/conqa/serverless-openapi-documentation/compare/v1.1.0...HEAD
[1.1.0]: https://github.com/conqa/serverless-openapi-documentation/compare/v1.0.4...v1.1.0
[1.0.4]: https://github.com/conqa/serverless-openapi-documentation/compare/v1.0.3...v1.0.4
[1.0.3]: https://github.com/conqa/serverless-openapi-documentation/tree/v1.0.3
[1.0.3]: https://github.com/conqa/serverless-openapi-documentation/compare/v1.0.2...v1.0.3
[1.0.2]: https://github.com/conqa/serverless-openapi-documentation/compare/v1.0.1...v1.0.2
[1.0.1]: https://github.com/conqa/serverless-openapi-documentation/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/conqa/serverless-openapi-documentation/tree/v1.0.0

44

DefinitionGenerator.d.ts

@@ -1,17 +0,17 @@

import { IDefinition, IDefinitionConfig, IServerlessFunctionConfig } from './types';
import { Definition, DefinitionConfig, ServerlessFunctionConfig } from "./types";
export declare class DefinitionGenerator {
version: string;
definition: IDefinition;
config: IDefinitionConfig;
definition: Definition;
config: DefinitionConfig;
private root;
/**
* Constructor
* @param serviceDescriptor IServiceDescription
*/
constructor(config: IDefinitionConfig);
parse(): this;
constructor(config: DefinitionConfig, root: string);
parse(): Promise<this>;
validate(): {
valid: boolean;
context: string[];
warnings: any[];
error?: any[];
context: Array<string>;
warnings: Array<any>;
error?: Array<any>;
};

@@ -22,14 +22,4 @@ /**

*/
readFunctions(config: IServerlessFunctionConfig[]): void;
readFunctions(config: Array<ServerlessFunctionConfig>): void;
/**
* Cleans schema objects to make them OpenAPI compatible
* @param schema JSON Schema Object
*/
private cleanSchema(schema);
/**
* Walks through the schema object recursively and updates references to point to openapi's components
* @param schema JSON Schema Object
*/
private updateReferences(schema);
/**
* Generate Operation objects from the Serverless Config.

@@ -41,3 +31,3 @@ *

*/
private getOperationFromConfig(funcName, documentationConfig);
private getOperationFromConfig;
/**

@@ -47,3 +37,3 @@ * Derives Path, Query and Request header parameters from Serverless documentation

*/
private getParametersFromConfig(documentationConfig);
private getParametersFromConfig;
/**

@@ -53,4 +43,4 @@ * Derives request body schemas from event documentation configuration

*/
private getRequestBodiesFromConfig(documentationConfig);
private attachExamples(target, config);
private getRequestBodiesFromConfig;
private attachExamples;
/**

@@ -60,5 +50,5 @@ * Gets response bodies from documentation config

*/
private getResponsesFromConfig(documentationConfig);
private getResponseContent(response);
private getHttpEvents(funcConfig);
private getResponsesFromConfig;
private getResponseContent;
private getHttpEvents;
}
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("lodash");
// tslint:disable-next-line no-submodule-imports
const validate_1 = require("swagger2openapi/validate");
const uuid = require("uuid");
const parse_1 = require("./parse");
const utils_1 = require("./utils");

@@ -10,41 +20,37 @@ class DefinitionGenerator {

* Constructor
* @param serviceDescriptor IServiceDescription
*/
constructor(config) {
constructor(config, root) {
// The OpenAPI version we currently validate against
this.version = '3.0.0';
this.version = "3.0.0";
// Base configuration object
this.definition = {
openapi: this.version,
components: {},
components: {}
};
this.config = utils_1.clone(config);
this.config = _.cloneDeep(config);
this.root = root;
}
parse() {
const { title = '', description = '', version = uuid.v4(), models, } = this.config;
utils_1.merge(this.definition, {
openapi: this.version,
info: { title, description, version },
paths: {},
components: {
schemas: {},
securitySchemes: {},
},
});
if (utils_1.isIterable(models)) {
for (const model of models) {
if (!model.schema) {
continue;
return __awaiter(this, void 0, void 0, function* () {
const { title = "", description = "", version = uuid.v4(), models, security, securitySchemes, servers } = this.config;
_.merge(this.definition, {
openapi: this.version,
info: { title, description, version },
paths: {},
components: {
schemas: {}
}
for (const definitionName of Object.keys(model.schema.definitions || {})) {
const definition = model.schema.definitions[definitionName];
if (typeof definition !== 'boolean') {
this.definition.components.schemas[definitionName] = this.cleanSchema(this.updateReferences(definition));
}
}
const schemaWithoutDefinitions = utils_1.omit(model.schema, ['definitions']);
this.definition.components.schemas[model.name] = this.cleanSchema(this.updateReferences(schemaWithoutDefinitions));
});
if (security) {
this.definition.security = security;
}
}
return this;
if (securitySchemes) {
this.definition.components.securitySchemes = securitySchemes;
}
if (servers) {
this.definition.servers = servers;
}
this.definition.components.schemas = yield parse_1.parseModels(models, this.root);
return this;
});
}

@@ -75,7 +81,7 @@ validate() {

[`/${httpEventConfig.path}`]: {
[httpEventConfig.method.toLowerCase()]: this.getOperationFromConfig(funcConfig._functionName, httpEventConfig.documentation),
},
[httpEventConfig.method.toLowerCase()]: this.getOperationFromConfig(funcConfig._functionName, httpEventConfig.documentation)
}
};
// merge path configuration into main configuration
utils_1.merge(this.definition.paths, pathConfig);
_.merge(this.definition.paths, pathConfig);
}

@@ -86,35 +92,2 @@ }

/**
* Cleans schema objects to make them OpenAPI compatible
* @param schema JSON Schema Object
*/
cleanSchema(schema) {
// Clone the schema for manipulation
const cleanedSchema = utils_1.clone(schema);
// Strip $schema from schemas
if (cleanedSchema.$schema) {
delete cleanedSchema.$schema;
}
// Return the cleaned schema
return cleanedSchema;
}
/**
* Walks through the schema object recursively and updates references to point to openapi's components
* @param schema JSON Schema Object
*/
updateReferences(schema) {
const cloned = utils_1.clone(schema);
if (cloned.$ref) {
cloned.$ref = cloned.$ref.replace('#/definitions', '#/components/schemas');
}
else {
for (const key of Object.getOwnPropertyNames(cloned)) {
const value = cloned[key];
if (typeof value === 'object') {
cloned[key] = this.updateReferences(value);
}
}
}
return cloned;
}
/**
* Generate Operation objects from the Serverless Config.

@@ -128,3 +101,3 @@ *

const operationObj = {
operationId: funcName,
operationId: funcName
};

@@ -157,14 +130,14 @@ if (documentationConfig.summary) {

// Build up parameters from configuration for each parameter type
for (const type of ['path', 'query', 'header', 'cookie']) {
for (const type of ["path", "query", "header", "cookie"]) {
let paramBlock;
if (type === 'path' && documentationConfig.pathParams) {
if (type === "path" && documentationConfig.pathParams) {
paramBlock = documentationConfig.pathParams;
}
else if (type === 'query' && documentationConfig.queryParams) {
else if (type === "query" && documentationConfig.queryParams) {
paramBlock = documentationConfig.queryParams;
}
else if (type === 'header' && documentationConfig.requestHeaders) {
else if (type === "header" && documentationConfig.requestHeaders) {
paramBlock = documentationConfig.requestHeaders;
}
else if (type === 'cookie' && documentationConfig.cookieParams) {
else if (type === "cookie" && documentationConfig.cookieParams) {
paramBlock = documentationConfig.cookieParams;

@@ -180,26 +153,26 @@ }

in: type,
description: parameter.description || '',
required: parameter.required || false,
description: parameter.description || "",
required: parameter.required || false // Note: all path parameters must be required
};
// if type is path, then required must be true (@see OpenAPI 3.0-RC1)
if (type === 'path') {
if (type === "path") {
parameterConfig.required = true;
}
else if (type === 'query') {
else if (type === "query") {
parameterConfig.allowEmptyValue = parameter.allowEmptyValue || false; // OpenAPI default is false
if ('allowReserved' in parameter) {
if ("allowReserved" in parameter) {
parameterConfig.allowReserved = parameter.allowReserved || false;
}
}
if ('deprecated' in parameter) {
if ("deprecated" in parameter) {
parameterConfig.deprecated = parameter.deprecated;
}
if ('style' in parameter) {
if ("style" in parameter) {
parameterConfig.style = parameter.style;
parameterConfig.explode = parameter.explode
? parameter.explode
: parameter.style === 'form';
: parameter.style === "form";
}
if (parameter.schema) {
parameterConfig.schema = this.cleanSchema(parameter.schema);
parameterConfig.schema = utils_1.cleanSchema(parameter.schema);
}

@@ -234,8 +207,10 @@ if (parameter.example) {

// get schema reference information
const requestModel = this.config.models.filter((model) => model.name === documentationConfig.requestModels[requestModelType]).pop();
const requestModel = this.config.models
.filter(model => model.name === documentationConfig.requestModels[requestModelType])
.pop();
if (requestModel) {
const reqModelConfig = {
schema: {
$ref: `#/components/schemas/${documentationConfig.requestModels[requestModelType]}`,
},
$ref: `#/components/schemas/${documentationConfig.requestModels[requestModelType]}`
}
};

@@ -245,9 +220,11 @@ this.attachExamples(requestModel, reqModelConfig);

content: {
[requestModelType]: reqModelConfig,
},
[requestModelType]: reqModelConfig
}
};
if (documentationConfig.requestBody && 'description' in documentationConfig.requestBody) {
reqBodyConfig.description = documentationConfig.requestBody.description;
if (documentationConfig.requestBody &&
"description" in documentationConfig.requestBody) {
reqBodyConfig.description =
documentationConfig.requestBody.description;
}
utils_1.merge(requestBodies, reqBodyConfig);
_.merge(requestBodies, reqBodyConfig);
}

@@ -260,6 +237,6 @@ }

if (target.examples && Array.isArray(target.examples)) {
utils_1.merge(config, { examples: utils_1.clone(target.examples) });
_.merge(config, { examples: _.cloneDeep(target.examples) });
}
else if (target.example) {
utils_1.merge(config, { example: utils_1.clone(target.example) });
_.merge(config, { example: _.cloneDeep(target.example) });
}

@@ -276,6 +253,6 @@ }

const methodResponseConfig = {
description: ((response.responseBody && 'description' in response.responseBody)
description: response.responseBody && "description" in response.responseBody
? response.responseBody.description
: `Status ${response.statusCode} Response`),
content: this.getResponseContent(response.responseModels),
: `Status ${response.statusCode} Response`,
content: this.getResponseContent(response.responseModels)
};

@@ -286,11 +263,11 @@ if (response.responseHeaders) {

methodResponseConfig.headers[header.name] = {
description: header.description || `${header.name} header`,
description: header.description || `${header.name} header`
};
if (header.schema) {
methodResponseConfig.headers[header.name].schema = this.cleanSchema(header.schema);
methodResponseConfig.headers[header.name].schema = utils_1.cleanSchema(header.schema);
}
}
}
utils_1.merge(responses, {
[response.statusCode]: methodResponseConfig,
_.merge(responses, {
[response.statusCode]: methodResponseConfig
});

@@ -304,11 +281,11 @@ }

for (const responseKey of Object.keys(response)) {
const responseModel = this.config.models.find((model) => model.name === response[responseKey]);
const responseModel = this.config.models.find(model => model.name === response[responseKey]);
if (responseModel) {
const resModelConfig = {
schema: {
$ref: `#/components/schemas/${response[responseKey]}`,
},
$ref: `#/components/schemas/${response[responseKey]}`
}
};
this.attachExamples(responseModel, resModelConfig);
utils_1.merge(content, { [responseKey]: resModelConfig });
_.merge(content, { [responseKey]: resModelConfig });
}

@@ -319,3 +296,3 @@ }

getHttpEvents(funcConfig) {
return funcConfig.filter((event) => event.http ? true : false);
return funcConfig.filter(event => (event.http ? true : false));
}

@@ -322,0 +299,0 @@ }

@@ -1,2 +0,2 @@

import { ServerlessOpenApiDocumentation } from './ServerlessOpenApiDocumentation';
import { ServerlessOpenApiDocumentation } from "./ServerlessOpenApiDocumentation";
export default ServerlessOpenApiDocumentation;
{
"name": "@conqa/serverless-openapi-documentation",
"version": "1.0.4",
"version": "1.1.0",
"description": "Serverless 1.0 plugin to generate OpenAPI V3 documentation from serverless configuration",
"main": "index.js",
"engines": {
"node": ">=6.0.0",
"npm": ">=3.8.6"
},
"repository": {

@@ -23,13 +27,14 @@ "type": "git",

"scripts": {
"test": "jest",
"test:build": "jest -c '{}' build",
"test:coverage": "jest --coverage",
"lint": "tslint -p tsconfig.json --type-check -c tslint.json",
"preversion": "yarn lint && yarn build && yarn test:build && changelog-verify CHANGELOG.md",
"test": "jest -c ./jest.config.js",
"test:build": "jest -c '{ \"testRegex\": \".spec.js$\"}' build",
"test:coverage": "jest -c ./jest.config.js --coverage",
"lint": "eslint --ext .ts,.tsx .",
"lint:fix": "npm run lint -- --fix",
"preversion": "npm run lint && npm run build && npm run test:build && changelog-verify CHANGELOG.md",
"version": "version-changelog CHANGELOG.md && changelog-verify CHANGELOG.md && git add CHANGELOG.md",
"release": "cd build && npm publish",
"test:project": "cd test/project && yarn sls openapi generate",
"test:project": "cd test/project && ./node_modules/.bin/sls openapi generate",
"test:prepare": "scripts/prepareTests.bash",
"build:link": "yarn build && cd build && yarn link",
"build:watch": "yarn build && tsc --watch",
"build:link": "npm run build && cd build && npm link",
"build:watch": "npm run build && tsc --watch",
"build": "scripts/build.bash"

@@ -42,14 +47,21 @@ },

"@types/jest": "^20.0.2",
"@types/js-yaml": "^3.5.31",
"@types/js-yaml": "^3.12.1",
"@types/json-schema": "^7.0.3",
"@types/node": "^8.0.7",
"@types/uuid": "^3.0.0",
"@types/lodash": "^4.14.123",
"@types/node": "^8.10.48",
"@types/serverless": "^1.18.2",
"@types/uuid": "^3.4.4",
"@typescript-eslint/eslint-plugin": "^1.7.0",
"@typescript-eslint/parser": "^1.7.0",
"changelog-verify": "^1.0.4",
"jest": "^20.0.4",
"serverless": "^1.16.1",
"ts-jest": "^20.0.6",
"eslint": "^5.16.0",
"eslint-config-prettier": "^4.2.0",
"eslint-plugin-prettier": "^3.0.1",
"jest": "^24.8.0",
"openapi-types": "^1.3.4",
"prettier": "^1.17.0",
"serverless": "^1.41.1",
"ts-jest": "^24.0.2",
"ts-node": "^3.1.0",
"tslint": "^5.4.3",
"tslint-config-temando": "^1.1.4",
"typescript": "^2.4.1",
"typescript": "^3.4.5",
"version-changelog": "^2.1.0"

@@ -62,3 +74,4 @@ },

"js-yaml": "^3.8.4",
"lutils": "^2.4.0",
"json-schema-ref-parser": "^6.1.0",
"lodash": "^4.17.11",
"swagger2openapi": "^2.5.0",

@@ -65,0 +78,0 @@ "uuid": "^3.1.0"

# Serverless OpenAPI Documentation Plugin
[![NPM](https://img.shields.io/npm/v/serverless-openapi-documentation.svg)](https://npmjs.org/packages/serverless-openapi-documentation/)
[![Travis CI](https://img.shields.io/travis/temando/serverless-openapi-documentation.svg)](https://travis-ci.org/temando/serverless-openapi-documentation)
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
[![NPM](https://img.shields.io/npm/v/@conqa/serverless-openapi-documentation.svg)](https://npmjs.org/packages/@conqa/serverless-openapi-documentation/)
[![Travis CI](https://img.shields.io/travis/conqa/serverless-openapi-documentation.svg)](https://travis-ci.org/conqa/serverless-openapi-documentation)
Generates [**OpenAPI 3.0.0**](https://github.com/OAI/OpenAPI-Specification/blob/3.0.0/versions/3.0.0.md) documentation from serverless configuration files. OpenAPI is formerly known as Swagger. The configuration is inspired by the format used in [serverless-aws-documentation](https://www.npmjs.com/package/serverless-aws-documentation).
Works well with [Lincoln OpenAPI Renderer](https://github.com/temando/open-api-renderer).
Works well with [ReDoc](https://github.com/Rebilly/ReDoc).

@@ -23,3 +22,3 @@ ---

- [`methodResponses`](#methodresponses)
- [Example Configuration](#example-configuration)
- [Example configuration](#example-configuration)
- [Install](#install)

@@ -64,2 +63,6 @@

description: 'This is my API'
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#securitySchemeObject
securitySchemes: {}
# https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#security-requirement-object
security: {}
models: {}

@@ -94,3 +97,6 @@ ```

* `contentType`: the content type of the described request/response (ie. `application/json` or `application/xml`).
* `schema`: The JSON Schema ([website](http://json-schema.org/)) that describes the model. You can either use inline `YAML` to define these, or refer to an external schema file as below
* `schema`: The JSON Schema ([website](http://json-schema.org/)) that describes the model. You can either:
- use inline `YAML` to define these
- use serverless' functionality to merge in external schema file
- specify a path to json schema in which case if you reuse some types in multiple schemas - they will be included in resulting components once instead of duplicated for each referencing schema

@@ -101,12 +107,4 @@ ```yml

models:
- name: "ErrorResponse"
description: "This is an error"
contentType: "application/json"
schema: ${file(models/ErrorResponse.json)}
- name: "PutDocumentResponse"
description: "PUT Document response model (external reference example)"
contentType: "application/json"
schema: ${file(models/PutDocumentResponse.json)}
- name: "PutDocumentRequest"
description: "PUT Document request model (inline example)"
description: "Inline schema example"
contentType: "application/json"

@@ -121,2 +119,10 @@ schema:

type: "string"
- name: "PutDocumentResponse"
description: "External file merge example"
contentType: "application/json"
schema: ${file(models/PutDocumentResponse.json)}
- name: "ErrorResponse"
description: "Path to a schema example"
contentType: "application/json"
schema: models/ErrorResponse.json
```

@@ -320,3 +326,3 @@

```bash
npm install serverless-openapi-documentation --save-dev
npm install @conqa/serverless-openapi-documentation --save-dev
```

@@ -326,3 +332,3 @@

```bash
yarn add serverless-openapi-documentation --dev
yarn add @conqa/serverless-openapi-documentation --dev
```

@@ -334,3 +340,3 @@

plugins:
- serverless-openapi-documentation
- @conqa/serverless-openapi-documentation
```

@@ -337,0 +343,0 @@

@@ -1,2 +0,24 @@

import { ILog } from './types';
import * as Serverless from "serverless";
import { Format, DefinitionConfig } from "./types";
interface Options {
indent: number;
format: Format;
output: string;
}
interface ProcessedInput {
options: Options;
}
interface CustomVars {
documentation: DefinitionConfig;
}
interface Service {
custom: CustomVars;
}
interface Variables {
service: Service;
}
interface FullServerless extends Serverless {
variables: Variables;
processedInput: ProcessedInput;
}
export declare class ServerlessOpenApiDocumentation {

@@ -7,4 +29,2 @@ hooks: any;

private serverless;
/** CLI options */
private options;
/** Serverless Service Custom vars */

@@ -17,13 +37,14 @@ private customVars;

*/
constructor(serverless: any, options: any);
log: ILog;
constructor(serverless: FullServerless, options: any);
private log;
/**
* Generates OpenAPI Documentation based on serverless configuration and functions
*/
generate(): Promise<void>;
/**
* Processes CLI input by reading the input from serverless
* @returns config IConfigType
*/
private processCliInput();
/**
* Generates OpenAPI Documentation based on serverless configuration and functions
*/
private generate();
private processCliInput;
}
export {};
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const c = require("chalk");
const chalk_1 = require("chalk");
const fs = require("fs");
const YAML = require("js-yaml");
const _ = require("lodash");
const util_1 = require("util");
const DefinitionGenerator_1 = require("./DefinitionGenerator");
const utils_1 = require("./utils");
const types_1 = require("./types");
class ServerlessOpenApiDocumentation {

@@ -17,8 +26,6 @@ /**

this.log = (...str) => {
process.stdout.write(str.join(' '));
process.stdout.write(str.join(" "));
};
// pull the serverless instance into our class vars
this.serverless = serverless;
// pull the CLI options into our class vars
this.options = options;
// Serverless service custom variables

@@ -31,30 +38,85 @@ this.customVars = this.serverless.variables.service.custom;

generate: {
lifecycleEvents: [
'serverless',
],
usage: 'Generate OpenAPI v3 Documentation',
lifecycleEvents: ["serverless"],
usage: "Generate OpenAPI v3 Documentation",
options: {
output: {
usage: 'Output file location [default: openapi.yml|json]',
shortcut: 'o',
usage: "Output file location [default: openapi.yml|json]",
shortcut: "o"
},
format: {
usage: 'OpenAPI file format (yml|json) [default: yml]',
shortcut: 'f',
usage: "OpenAPI file format (yml|json) [default: yml]",
shortcut: "f"
},
indent: {
usage: 'File indentation in spaces [default: 2]',
shortcut: 'i',
},
},
},
},
},
usage: "File indentation in spaces [default: 2]",
shortcut: "i"
}
}
}
}
}
};
// Declare the hooks our plugin is interested in
this.hooks = {
'openapi:generate:serverless': this.generate.bind(this),
"openapi:generate:serverless": this.generate.bind(this)
};
}
/**
* Generates OpenAPI Documentation based on serverless configuration and functions
*/
generate() {
return __awaiter(this, void 0, void 0, function* () {
this.log(chalk_1.default.bold.underline("OpenAPI v3 Documentation Generator\n\n"));
// Instantiate DocumentGenerator
const generator = new DefinitionGenerator_1.DefinitionGenerator(this.customVars.documentation, this.serverless.config.servicePath);
yield generator.parse();
// Map function configurations
const funcConfigs = this.serverless.service
.getAllFunctions()
.map(functionName => {
const func = this.serverless.service.getFunction(functionName);
return _.merge({ _functionName: functionName }, func);
});
// Add Paths to OpenAPI Output from Function Configuration
generator.readFunctions(funcConfigs);
// Process CLI Input options
const config = this.processCliInput();
this.log(`${chalk_1.default.bold.yellow("[VALIDATION]")} Validating OpenAPI generated output\n`);
const validation = generator.validate();
if (validation.valid) {
this.log(`${chalk_1.default.bold.green("[VALIDATION]")} OpenAPI valid: ${chalk_1.default.bold.green("true")}\n\n`);
}
else {
this.log(`${chalk_1.default.bold.red("[VALIDATION]")} Failed to validate OpenAPI document: \n\n`);
this.log(`${chalk_1.default.bold.green("Context:")} ${JSON.stringify(validation.context, null, 2)}\n`);
if (typeof validation.error === "string") {
this.log(`${validation.error}\n\n`);
}
else {
for (const info of validation.error) {
this.log(chalk_1.default.grey("\n\n--------\n\n"));
this.log(" ", chalk_1.default.blue(info.dataPath), "\n");
this.log(" ", info.schemaPath, chalk_1.default.bold.yellow(info.message));
this.log(chalk_1.default.grey("\n\n--------\n\n"));
this.log(`${util_1.inspect(info, { colors: true, depth: 2 })}\n\n`);
}
}
}
const { definition } = generator;
// Output the OpenAPI document to the correct format
let output;
switch (config.format.toLowerCase()) {
case "json":
output = JSON.stringify(definition, null, config.indent);
break;
case "yaml":
default:
output = YAML.safeDump(definition, { indent: config.indent });
break;
}
fs.writeFileSync(config.file, output);
this.log(`${chalk_1.default.bold.green("[OUTPUT]")} To "${chalk_1.default.bold.red(config.file)}"\n`);
});
}
/**
* Processes CLI input by reading the input from serverless

@@ -65,71 +127,20 @@ * @returns config IConfigType

const config = {
format: 'yaml',
file: 'openapi.yml',
indent: 2,
format: types_1.Format.yaml,
file: "openapi.yml",
indent: 2
};
config.indent = this.serverless.processedInput.options.indent || 2;
config.format = this.serverless.processedInput.options.format || 'yaml';
if (['yaml', 'json'].indexOf(config.format.toLowerCase()) < 0) {
config.format =
this.serverless.processedInput.options.format || types_1.Format.yaml;
if ([types_1.Format.yaml, types_1.Format.json].indexOf(config.format) < 0) {
throw new Error('Invalid Output Format Specified - must be one of "yaml" or "json"');
}
config.file = this.serverless.processedInput.options.output ||
((config.format === 'yaml') ? 'openapi.yml' : 'openapi.json');
this.log(`${c.bold.green('[OPTIONS]')}`, `format: "${c.bold.red(config.format)}",`, `output file: "${c.bold.red(config.file)}",`, `indentation: "${c.bold.red(String(config.indent))}"\n\n`);
config.file =
this.serverless.processedInput.options.output ||
(config.format === "yaml" ? "openapi.yml" : "openapi.json");
this.log(`${chalk_1.default.bold.green("[OPTIONS]")}`, `format: "${chalk_1.default.bold.red(config.format)}",`, `output file: "${chalk_1.default.bold.red(config.file)}",`, `indentation: "${chalk_1.default.bold.red(String(config.indent))}"\n\n`);
return config;
}
/**
* Generates OpenAPI Documentation based on serverless configuration and functions
*/
generate() {
this.log(c.bold.underline('OpenAPI v3 Documentation Generator\n\n'));
// Instantiate DocumentGenerator
const generator = new DefinitionGenerator_1.DefinitionGenerator(this.customVars.documentation);
generator.parse();
// Map function configurations
const funcConfigs = this.serverless.service.getAllFunctions().map((functionName) => {
const func = this.serverless.service.getFunction(functionName);
return utils_1.merge({ _functionName: functionName }, func);
});
// Add Paths to OpenAPI Output from Function Configuration
generator.readFunctions(funcConfigs);
// Process CLI Input options
const config = this.processCliInput();
this.log(`${c.bold.yellow('[VALIDATION]')} Validating OpenAPI generated output\n`);
const validation = generator.validate();
if (validation.valid) {
this.log(`${c.bold.green('[VALIDATION]')} OpenAPI valid: ${c.bold.green('true')}\n\n`);
}
else {
this.log(`${c.bold.red('[VALIDATION]')} Failed to validate OpenAPI document: \n\n`);
this.log(`${c.bold.green('Context:')} ${JSON.stringify(validation.context, null, 2)}\n`);
if (typeof validation.error === 'string') {
this.log(`${validation.error}\n\n`);
}
else {
for (const info of validation.error) {
this.log(c.grey('\n\n--------\n\n'));
this.log(' ', c.blue(info.dataPath), '\n');
this.log(' ', info.schemaPath, c.bold.yellow(info.message));
this.log(c.grey('\n\n--------\n\n'));
this.log(`${util_1.inspect(info, { colors: true, depth: 2 })}\n\n`);
}
}
}
const { definition } = generator;
// Output the OpenAPI document to the correct format
let output;
switch (config.format.toLowerCase()) {
case 'json':
output = JSON.stringify(definition, null, config.indent);
break;
case 'yaml':
default:
output = YAML.safeDump(definition, { indent: config.indent });
break;
}
fs.writeFileSync(config.file, output);
this.log(`${c.bold.green('[OUTPUT]')} To "${c.bold.red(config.file)}"\n`);
}
}
exports.ServerlessOpenApiDocumentation = ServerlessOpenApiDocumentation;
//# sourceMappingURL=ServerlessOpenApiDocumentation.js.map

@@ -1,22 +0,30 @@

import { JSONSchema7 } from 'json-schema';
export interface IModels {
import { JSONSchema7 } from "json-schema";
import { OpenAPIV3 } from "openapi-types";
export interface Model {
name: string;
description: string;
contentType: string;
schema: JSONSchema7;
examples: any[];
schema: string | JSONSchema7;
examples: Array<any>;
example: object;
}
export interface IDefinitionConfig {
export interface DefinitionConfig {
title: string;
description: string;
version?: string;
models: IModels[];
securitySchemes: OpenAPIV3.SecuritySchemeObject;
security: Array<OpenAPIV3.SecurityRequirementObject>;
servers: Array<OpenAPIV3.ServerObject>;
models: Array<Model>;
}
export interface IDefinitionType {
export declare enum Format {
yaml = "yaml",
json = "json"
}
export interface DefinitionType {
file: string;
format: 'yaml' | 'json';
format: Format;
indent: number;
}
export interface IServerlessFunctionConfig {
export interface ServerlessFunctionConfig {
_functionName: string;

@@ -26,6 +34,6 @@ handler: string;

environment?: object;
events?: any[];
events?: Array<any>;
}
export interface IOperation {
tags?: string[];
export interface Operation {
tags?: Array<string>;
summary?: string;

@@ -35,3 +43,3 @@ description?: string;

operationId?: string;
parameters?: IParameterConfig[];
parameters?: Array<ParameterConfig>;
requestBody?: any;

@@ -41,8 +49,8 @@ responses?: any;

deprecated?: boolean;
security?: any[];
servers?: any[];
security?: Array<any>;
servers?: Array<any>;
}
export interface IParameterConfig {
export interface ParameterConfig {
name: string;
in: 'path' | 'query' | 'header' | 'cookie';
in: "path" | "query" | "header" | "cookie";
description: string;

@@ -53,19 +61,19 @@ required?: boolean;

allowEmptyValue?: boolean;
style?: 'form' | 'simple';
style?: "form" | "simple";
explode?: boolean;
allowReserved?: boolean;
example?: any;
examples?: any[];
examples?: Array<any>;
content?: Map<string, any>;
}
export interface IDefinition {
export interface Definition {
openapi: string;
info: any;
servers?: any[];
paths: any;
info?: any;
servers?: Array<any>;
paths?: any;
components?: any;
security?: any[];
tags?: any[];
externalDocs: any;
security?: Array<any>;
tags?: Array<any>;
externalDocs?: any;
}
export declare type ILog = (...str: string[]) => void;
export declare type ILog = (...str: Array<string>) => void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Format;
(function (Format) {
Format["yaml"] = "yaml";
Format["json"] = "json";
})(Format = exports.Format || (exports.Format = {}));
//# sourceMappingURL=types.js.map

@@ -1,5 +0,1 @@

import { IMerge } from 'lutils';
export declare const merge: IMerge;
export declare const clone: <S>(source: S) => S;
export declare function isIterable(obj: any): boolean;
export declare function omit<T extends object>(obj: T, keys: string[]): T;
export declare const cleanSchema: (schema: any) => any;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const lutils_1 = require("lutils");
exports.merge = new lutils_1.Merge({ depth: 100 }).merge;
exports.clone = new lutils_1.Clone({ depth: 100 }).clone;
function isIterable(obj) {
if (obj === null || obj === undefined) {
return false;
}
return typeof obj[Symbol.iterator] === 'function';
}
exports.isIterable = isIterable;
function omit(obj, keys) {
const cloned = exports.clone(obj);
for (const key of keys) {
delete cloned[key];
}
return cloned;
}
exports.omit = omit;
const _ = require("lodash");
exports.cleanSchema = schema => _.omit(schema, "$schema", "definitions");
//# sourceMappingURL=utils.js.map

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc