Skip to content

Commit

Permalink
init.
Browse files Browse the repository at this point in the history
  • Loading branch information
xicilion committed Apr 20, 2021
0 parents commit 2d2f225
Show file tree
Hide file tree
Showing 8 changed files with 384 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
.vscode
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Swagger to fibjs Codegen

This package generates a fibjs class from a [swagger specification file](https://github.com/wordnik/swagger-spec). The code is generated using [mustache templates](https://github.com/mtennoe/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).

The generator is based on [superagent](https://github.com/visionmedia/superagent) and can be used for fibjs.

This fork was made to simplify some parts, add some more features, and tailor it more to specific use cases.

## Installation

```bash
fibjs --install fib-swagger
```

## cli

```bash
fibjs node-modules/fib-swagger/lib/cli -c Test gen test.json test.js
```

## Example Code

```javascript
var fs = require("fs");
var CodeGen = require("fib-swagger").CodeGen;

var file = "swagger/spec.json";
var swagger = JSON.parse(fs.readFileSync(file, "UTF-8"));
var tsSourceCode = CodeGen.getFibjstCode({
className: "Test",
swagger: swagger
});
console.log(tsSourceCode);
```
45 changes: 45 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict';

const fs = require('fs');
const pkg = require('../package.json');
const cli = require('commander');
const yaml = require('js-yaml').safeLoad;
const CodeGen = require('./index.js').CodeGen;

cli
.version(pkg.version)
.command('gen <file> <out>')
.description('Generate from Swagger file')
.option('-c, --class <class>', 'Class name [Test]', 'Test')
.option('-l, --lint', 'Whether or not to run jslint on the generated code [false]')
.option('-b, --beautify', 'Whether or not to beautify the generated code [false]')
.action((file, out, options) => {
const fn = CodeGen.getFibjsCode;
options.lint = options.lint || false;
options.beautify = options.beautify || false;

const content = fs.readFileSync(file, 'utf-8');

var swagger;
try {
swagger = JSON.parse(content);
} catch (e) {
swagger = yaml(content);
}

const result = fn({
moduleName: options.module,
className: options.class,
swagger: swagger,
lint: options.lint,
beautify: options.beautify
});

fs.writeFileSync(out, result);
});

cli.parse(process.argv);

if (!cli.args.length) {
cli.help();
}
29 changes: 29 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
var fs = require('fs');
var path = require('path');
var jsyaml = require('js-yaml');
var CodeGen = require('swagger-typescript-codegen').CodeGen;

CodeGen.getFibjsCode = function (opt) {
var _opt = {};

if (opt) {
for (var k in opt)
_opt[k] = opt[k];
opt = _opt;
}

if (opt.swagger.openapi) {
opt.swagger.swagger = '2.0';
opt.swagger.securityDefinitions = opt.swagger.components.securitySchemes;
}

opt.template = {
class: fs.readFileSync(path.join(__dirname, "../templates/class.mustache"), 'utf-8'),
method: fs.readFileSync(path.join(__dirname, "../templates/method.mustache"), 'utf-8'),
type: fs.readFileSync(path.join(__dirname, "../templates/type.mustache"), 'utf-8')
};

return CodeGen.getCustomCode(opt);
};

exports.CodeGen = CodeGen;
14 changes: 14 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "fib-swagger",
"version": "1.0.0",
"description": "Swagger to fibjs Codegen",
"repository": "",
"main": "lib/index.js",
"keywords": "",
"author": "",
"license": "ISC",
"dependencies": {
"swagger-typescript-codegen": "^3.2.2",
"js-yaml": "^3.14.1"
}
}
157 changes: 157 additions & 0 deletions templates/class.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*jshint -W069 */
/**
* {{&description}}
* @class {{&className}}
* @param {(string|object)} [domainOrOptions] - The project domain or options object. If object, see the object's optional properties.
* @param {string} [domainOrOptions.domain] - The project domain
* @param {object} [domainOrOptions.token] - auth token - object with value property and optional headerOrQueryName and isQuery properties
*/
{{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} {{&className}} = (function(){
'use strict';
{{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} http = require('http');
{{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} util = require('util');

function {{&className}}(options){
{{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} domain = (typeof options === 'object') ? options.domain : options;
this.domain = domain ? domain : '{{&domain}}';
if(this.domain.length === 0) {
throw new Error('Domain parameter must be specified as a string.');
}
this.headers = options.headers || {};
{{#isSecure}}
{{#isSecureToken}}
this.token = (typeof options === 'object') ? (options.token ? options.token : {}) : {};
{{/isSecureToken}}
{{#isSecureApiKey}}
this.apiKey = (typeof options === 'object') ? (options.apiKey ? options.apiKey : {}) : {};
{{/isSecureApiKey}}
{{#isSecureBasic}}
this.basic = (typeof options === 'object') ? (options.basic ? options.basic : {}) : {};
{{/isSecureBasic}}
{{/isSecure}}
}

function mergeQueryParams(parameters, queryParameters) {
if (parameters.$queryParameters) {
Object.keys(parameters.$queryParameters)
.forEach(function(parameterName) {
{{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} parameter = parameters.$queryParameters[parameterName];
queryParameters[parameterName] = parameter;
});
}
return queryParameters;
}

function request(method, url, parameters, body, headers, queryParameters, form) {
{{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} req = {};

if(Object.keys(queryParameters).length > 0) {
req.query = queryParameters;
}
if(Object.keys(headers).length > 0) {
req.headers = headers;
}

if(Object.keys(form).length > 0) {
req.body = form;
}else if(typeof(body) === 'object' && !(body instanceof Buffer)) {
if(Object.keys(body).length > 0) {
req.json = body;
}
} else if(body) {
req.body = body;
}

var response = http.request(method, url, req);

if (response.statusCode >= 200 && response.statusCode <= 299) {
return response.data;
}

throw new Error(response.data);
}

{{#isSecure}}
{{#isSecureToken}}
/**
* Set Token
* @method
* @name {{&className}}#setToken
* @param {string} value - token's value
* @param {string} headerOrQueryName - the header or query name to send the token at
* @param {boolean} isQuery - true if send the token as query param, otherwise, send as header param
*/
{{&className}}.prototype.setToken = function (value, headerOrQueryName, isQuery) {
this.token.value = value;
this.token.headerOrQueryName = headerOrQueryName;
this.token.isQuery = isQuery;
};
{{/isSecureToken}}
{{#isSecureApiKey}}
/**
* Set Api Key
* @method
* @name {{&className}}#setApiKey
* @param {string} value - apiKey's value
* @param {string} headerOrQueryName - the header or query name to send the apiKey at
* @param {boolean} isQuery - true if send the apiKey as query param, otherwise, send as header param
*/
{{&className}}.prototype.setApiKey = function (value, headerOrQueryName, isQuery) {
this.apiKey.value = value;
this.apiKey.headerOrQueryName = headerOrQueryName;
this.apiKey.isQuery = isQuery;
};
{{/isSecureApiKey}}
{{#isSecureBasic}}
/**
* Set Basic Auth
* @method
* @name {{&className}}#setBasicAuth
* @param {string} username
* @param {string} password
*/
{{&className}}.prototype.setBasicAuth = function (username, password) {
this.basic.username = username;
this.basic.password = password;
};
{{/isSecureBasic}}
/**
* Set Auth headers
* @method
* @name {{&className}}#setAuthHeaders
* @param {object} headerParams - headers object
*/
{{&className}}.prototype.setAuthHeaders = function (headerParams) {
{{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} headers = headerParams ? headerParams : {};
{{#isSecureToken}}
if (!this.token.isQuery) {
if (this.token.headerOrQueryName) {
headers[this.token.headerOrQueryName] = this.token.value;
} else if (this.token.value) {
headers['Authorization'] = 'Bearer ' + this.token.value;
}
}
{{/isSecureToken}}
{{#isSecureApiKey}}
if (!this.apiKey.isQuery && this.apiKey.headerOrQueryName) {
headers[this.apiKey.headerOrQueryName] = this.apiKey.value;
}
{{/isSecureApiKey}}
{{#isSecureBasic}}
if (this.basic.username && this.basic.password) {
headers['Authorization'] = 'Basic ' + new Buffer(this.basic.username + ':' + this.basic.password).toString("base64");
}
{{/isSecureBasic}}
return headers;
};
{{/isSecure}}

{{#methods}}
{{> method}}
{{/methods}}

return {{&className}};
})();

exports.{{&className}} = {{&className}};
92 changes: 92 additions & 0 deletions templates/method.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* {{&summary}}
* @method
* @name {{&className}}#{{&methodName}}
* @param {object} parameters - method options and parameters
{{#parameters}}
{{^isSingleton}} * @param {{=<% %>=}}{<%&type%>}<%={{ }}=%> parameters.{{&camelCaseName}} - {{&description}}{{/isSingleton}}
{{/parameters}}
*/
{{&className}}.prototype.{{&methodName}} = function(parameters){
if(parameters === undefined) {
parameters = {};
}
{{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} domain = this.domain, path = '{{&path}}';
{{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} body = {}, queryParameters = {}, form = {};
{{#isES6}}let{{/isES6}}{{^isES6}}var{{/isES6}} headers = util.clone(this.headers);

{{#isSecure}}
headers = this.setAuthHeaders(headers);
{{/isSecure}}
{{#headers}}
headers['{{&name}}'] = [{{&value}}];
{{/headers}}

{{#parameters}}
{{#isQueryParameter}}
{{#isSingleton}}
queryParameters['{{&name}}'] = '{{&singleton}}';
{{/isSingleton}}
{{^isSingleton}}
{{#isPatternType}}
Object.keys(parameters).forEach(function(parameterName) {
if(new RegExp('{{&pattern}}').test(parameterName)){
queryParameters[parameterName] = parameters[parameterName];
}
});
{{/isPatternType}}
{{#default}}
/** set default value **/
queryParameters['{{&name}}'] = {{&default}};
{{/default}}

{{^isPatternType}}
if(parameters['{{&camelCaseName}}'] !== undefined){
queryParameters['{{&name}}'] = parameters['{{&camelCaseName}}'];
}
{{/isPatternType}}
{{/isSingleton}}
{{/isQueryParameter}}

{{#isPathParameter}}
path = path.replace('{{=<% %>=}}{<%&name%>}<%={{ }}=%>', parameters['{{&camelCaseName}}']);
{{/isPathParameter}}

{{#isHeaderParameter}}
{{#isSingleton}}
headers['{{&name}}'] = '{{&singleton}}';
{{/isSingleton}}
{{^isSingleton}}
if(parameters['{{&camelCaseName}}'] !== undefined){
headers['{{&name}}'] = parameters['{{&camelCaseName}}'];
}
{{/isSingleton}}
{{/isHeaderParameter}}

{{#isBodyParameter}}
if(parameters['{{&camelCaseName}}'] !== undefined){
body = parameters['{{&camelCaseName}}'];
}
{{/isBodyParameter}}

{{#isFormParameter}}
{{#isSingleton}}
form['{{&name}}'] = '{{&singleton}}';
{{/isSingleton}}
{{^isSingleton}}
if(parameters['{{&camelCaseName}}'] !== undefined){
form['{{&name}}'] = parameters['{{&camelCaseName}}'];
}
{{/isSingleton}}
{{/isFormParameter}}

{{#required}}
if(parameters['{{&camelCaseName}}'] === undefined)
throw new Error('Missing required {{&paramType}} parameter: {{&camelCaseName}}');
{{/required}}

{{/parameters}}
queryParameters = mergeQueryParams(parameters, queryParameters);

return request('{{method}}', domain + path, parameters, body, headers, queryParameters, form);
};
11 changes: 11 additions & 0 deletions templates/type.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{{#tsType}}
{{! must use different delimiters to avoid ambiguities when delimiters directly follow a literal brace {. }}
{{=<% %>=}}
<%#isRef%><%target%><%/isRef%><%!
%><%#isAtomic%><%&tsType%><%/isAtomic%><%!
%><%#isObject%>{<%#properties%>
'<%name%>'<%#optional%>?<%/optional%>: <%>type%><%/properties%>
}<%/isObject%><%!
%><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>>|<%#elementType%><%>type%><%/elementType%><%/isArray%>
<%={{ }}=%>
{{/tsType}}

0 comments on commit 2d2f225

Please sign in to comment.