Skip to content

Commit

Permalink
Merge pull request #2 from voicenter/feature/OFC-3
Browse files Browse the repository at this point in the history
Feature/ofc 3
  • Loading branch information
peterdee committed Apr 1, 2019
2 parents 7adbb0c + d6706d7 commit c885b75
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 50 deletions.
84 changes: 57 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,68 @@
# Swagger to JS & Typescript Codegen
[![Circle CI](https://circleci.com/gh/wcandillon/swagger-js-codegen.svg?style=svg)](https://circleci.com/gh/wcandillon/swagger-js-codegen) [![NPM version](http://img.shields.io/npm/v/swagger-js-codegen.svg?style=flat)](http://badge.fury.io/js/swagger-js-codegen)

## We are looking for a new maintainer
## Installation
```bash
npm install swagger-js-codegen
```

This project is no longer actively maintained by its creator. Please let us know if you would like to become a maintainer.
At the time we wrote this package, the swagger didn't have generators for JavaScript nor TypeScript. Now there are [great alternatives of this package available](https://github.com/swagger-api/swagger-codegen).
___

This package generates a nodejs, reactjs or angularjs class from a [swagger specification file](https://github.com/wordnik/swagger-spec). The code is generated using [mustache templates](https://github.com/wcandillon/swagger-js-codegen/tree/master/templates) and is quality checked by [jshint](https://github.com/jshint/jshint/) and beautified by [js-beautify](https://github.com/beautify-web/js-beautify).
## Multi-class generation (Node)

The typescript generator is based on [superagent](https://github.com/visionmedia/superagent) and can be used for both nodejs and the browser via browserify/webpack.
It is possible now to generate multiple controllers for Node.

Each controller will have a class that has several methods inside of it.

Each method represents an API, and has a default built-in response.

Definitions are generated as well.

**How it works:**

Definitions are generated before the APIs. File `expose.js` generates all of the necessary definitions and places them in the destination directory.

APIs are generated after that, based on the Mustache templates.

Module utilizes the custom Mustache templates (`multi-class` and `multi-method`).

Mustache generates a single file with a single ES5 class, that contains all of the methods.

File `splitter.js` splits the single file into several files with classes (based on tags in the original JSON). After the split is completed and methods are combined, they are saved as a controller file in the destination directory.

**Options:**

`className` **[REQUIRED]**: name of the single generated class. You can put any name.

`swagger` **[REQUIRED]**: loaded Swagger JSON file.

`multiple` **[REQUIRED]**: this option should be provided and should be set to `true` if you need a multi-class output.

`path` **[REQUIRED]**: location of the destination directories. `__dirname` is the best option, but you can provide your own destination path.

`controllersDirName` **[OPTIONAL]**: this is the name of the destination directory for **controllers**. `routes_generated` is the recommended name (it is used as default if this option was not provided).

`definitionsDirName` **[OPTIONAL]**: this is the name of the destination directory for **definitions**. `definitions_generated` is the recommended name (it is used as default if this option was not provided).

**Multi-class generation example:**

## Installation
```bash
npm install swagger-js-codegen
```
const { CodeGen } = require('swagger-js-codegen');
const fs = require('fs');
const file = 'swagger/swagger.json';
const spec = JSON.parse(fs.readFileSync(file, 'UTF-8'));
await CodeGen.getNodeCode({
className: 'Service',
swagger: spec,
multiple: true,
path: __dirname,
controllersDirName: 'routes_generated',
definitionsDirName: 'definitions_generated',
});
```

____
## Example
```javascript
var fs = require('fs');
Expand Down Expand Up @@ -80,24 +128,6 @@ In addition to the common options listed below, `getCustomCode()` *requires* a `
description: swagger object
```

If it is required to generate multiple files for Node (i. e. multiple methods based on the initial JSON) provide the following options:

multiple:
type: boolean
description: this option enables file splitting
path:
type: string
description: this option should contain the path to the project directory (__dirname)
example: '/Users/name/Projects/someProject/'
dir:
type: string
description: this option should contain the name of the directory with APIs
example: 'newAPIs'

If `multiple` option is provided, `path` and `dir` options **are required**

The `dir` folder will be created and generated files will be placed inside of it

### Template Variables
The following data are passed to the [mustache templates](https://github.com/janl/mustache.js):

Expand Down
33 changes: 24 additions & 9 deletions lib/codegen.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,17 +270,32 @@ var getViewForSwagger1 = function(opts, type){

/**
* Generate code based on the input file
* @param opts <OBJECT> - options for the file generation
* @param options <OBJECT> - options for the file generation
* @param type <STRING> - type of code / file to be generated (angular, custom, node, react, typescript)
* @returns {*}
*/
var getCode = function(opts, type) {
// check 'multiple' & all of the required parameters
if (opts.multiple) {
if (!(opts.dir && opts.path)) {
throw new Error('Missing some of the required parameters!');
}
var getCode = function(options, type) {
// check 'multiple' & all of the required parameters
const opts = _.cloneDeep(options);
if (options.multiple) {
if (!options.className) {
throw new Error('Missing the class name!');
}
if (!options.swagger) {
throw new Error('Missing the Swagger JSON!');
}
if (!options.path) {
throw new Error('Missing the destination path!');
}
if (!options.controllersDirName) {
opts.controllersDirName = 'routes_generated';
console.log('> swagger-js-codegen @ Controllers directory name not provided, using \'routes_generated\' as a default!');
}
if (!options.definitionsDirName) {
opts.definitionsDirName = 'definitions_generated';
console.log('> swagger-js-codegen @ Definitions directory name not provided, using \'definitions_generated\' as a default!');
}
}

// For Swagger Specification version 2.0 value of field 'swagger' must be a string '2.0'
var swaggerView = opts.swagger.swagger === '2.0' ? getViewForSwagger2(opts, type) : getViewForSwagger1(opts, type);
Expand All @@ -289,7 +304,7 @@ var getCode = function(opts, type) {
var data = formatter.format(swaggerView);

// expose definitions @ global scope
expose(opts.swagger.definitions, data.methods, opts.path);
expose(opts.swagger.definitions, data.methods, opts.path, opts.definitionsDirName);

if (type === 'custom') {
if (!_.isObject(opts.template) || !_.isString(opts.template.class) || !_.isString(opts.template.method)) {
Expand Down Expand Up @@ -348,7 +363,7 @@ var getCode = function(opts, type) {
return splitter.split(beautify(source, {
indent_size: 2,
max_preserve_newlines: 2
}), opts.className, opts.path, opts.dir);
}), opts.className, opts.path, opts.controllersDirName);
}
if (opts.beautify === undefined || opts.beautify === true) {
return beautify(source, { indent_size: 4, max_preserve_newlines: 2 });
Expand Down
11 changes: 6 additions & 5 deletions lib/expose.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ const { inspect } = require('util');
* Expose definitions objects, create files with objects
* @param {object} definitions - object that contain definitions objects
* @param {array} methods - array of the available methods
* @param {string} path - where to generate the files, resulting path will be path/definitions
* @param {string} path - where to generate the files, resulting path will be path/<directory>
* @param {string} directory - name of the directory
*/
function expose(definitions, methods, path) {
function expose(definitions, methods, path, directory) {
try {
// get list of the definitions
const list = Object.keys(definitions);
Expand All @@ -19,7 +20,7 @@ function expose(definitions, methods, path) {
}

// make sure that ~/definitions directory exists
const container = `${path}/definitions`;
const container = `${path}/${directory}`;
if (!fs.existsSync(container)) {
fs.mkdirSync(container);
}
Expand All @@ -40,8 +41,8 @@ function expose(definitions, methods, path) {
const refName = items['$ref'].split('/').slice(-1)[0];
parameters = `${parameters}
this['${prop}'] = [];
if (req.body['${prop}'].length && req.body['${prop}'].length > 0) {
req.body['${prop}'].forEach((object) => {
if (params['${prop}'].length && params['${prop}'].length > 0) {
params['${prop}'].forEach((object) => {
const ${refName} = new global.classes['${refName}'](req, res, object);
this.${prop}.push(${refName});
});
Expand Down
15 changes: 15 additions & 0 deletions lib/formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,21 @@ function format(data) {
// add objects
mutable.objects = objects;

// fix x-AuthFieldType TODO: need to rewrite it properly
mutable.methods.forEach((method, m) => {
method.parameters.forEach((parameter, p) => {
if (parameter['x-AuthFieldType']) {
const { propertyName: name, value } = parameter['x-AuthFieldType'];
if (!(name && value)) {
mutable.methods[m].parameters[p]['x-AuthFieldType'] = {
propertyName: parameter.name,
value: parameter['x-AuthFieldType'],
};
}
}
});
});

return mutable;
} catch (err) {
throw new Error(err.message || err);
Expand Down
2 changes: 1 addition & 1 deletion lib/splitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async function split(source, className, path, dir) {

// show conversion errors and warnings
if (warnings && warnings.length && warnings.length > 0) {
console.log('> codegen-splitter @ ES6 conversion warnings:\n', warnings);
console.log('> swagger-js-codegen @ ES6 conversion warnings:\n', warnings);
}

// create the source file
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "swagger-js-codegen",
"main": "./lib/codegen.js",
"version": "1.12.0",
"version": "2.0.0",
"description": "A Swagger codegen for JavaScript",
"scripts": {
"test": "grunt",
Expand All @@ -13,9 +13,12 @@
"bugs": {
"url": "https://github.com/wcandillon/swagger-js-codegen/issues"
},
"engines" : {
"node" : "^11.13.0"
},
"repository": {
"type": "git",
"url": "git://github.com/wcandillon/swagger-js-codegen.git"
"url": "git://github.com/voicenter/swagger-js-codegen"
},
"keywords": [
"swagger",
Expand Down
12 changes: 6 additions & 6 deletions templates/multi-method.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,26 @@
{{#parameters}}
{{#isQueryParameter}}
{{#x-AuthFieldType}}
var auth = await_FieldValidator.validate('{{&x-AuthFieldType.value}}', req.query['{{&x-AuthFieldType.propertyName}}'], req, res);
if (!auth) {
var auth{{&x-AuthFieldType.propertyName}} = await_FieldValidator.validate('{{&x-AuthFieldType.value}}', req.query['{{&x-AuthFieldType.propertyName}}'], req, res);
if (!auth{{&x-AuthFieldType.propertyName}}) {
return;
}
{{/x-AuthFieldType}}
var {{name}} = req.query['{{name}}'];
{{/isQueryParameter}}
{{#isPathParameter}}
{{#x-AuthFieldType}}
var auth = await_FieldValidator.validate('{{&x-AuthFieldType.value}}', req.params['{{&x-AuthFieldType.propertyName}}'], req, res);
if (!auth) {
var auth{{&x-AuthFieldType.propertyName}} = await_FieldValidator.validate('{{&x-AuthFieldType.value}}', req.params['{{&x-AuthFieldType.propertyName}}'], req, res);
if (!auth{{&x-AuthFieldType.propertyName}}) {
return;
}
{{/x-AuthFieldType}}
var {{name}} = req.params['{{name}}'];
{{/isPathParameter}}
{{#isBodyParameter}}
{{#x-AuthFieldType}}
var auth = await_FieldValidator.validate('{{&x-AuthFieldType.value}}', req.body['{{&x-AuthFieldType.propertyName}}'], req, res);
if (!auth) {
var auth{{&x-AuthFieldType.propertyName}} = await_FieldValidator.validate('{{&x-AuthFieldType.value}}', req.body['{{&x-AuthFieldType.propertyName}}'], req, res);
if (!auth{{&x-AuthFieldType.propertyName}}) {
return;
}
{{/x-AuthFieldType}}
Expand Down

0 comments on commit c885b75

Please sign in to comment.