From eabc7bf8e9aa459e1cb00481250b379c056e925d Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Apr 2016 12:53:31 +1000 Subject: [PATCH 01/61] The $http legacy promise methods success and error have been deprecated. Use the standard then method instead. If $httpProvider.useLegacyPromiseExtensions is set to false then these methods will throw $http/legacy error. --- templates/angular-request.mustache | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/templates/angular-request.mustache b/templates/angular-request.mustache index e55f870a..1c1a71c8 100644 --- a/templates/angular-request.mustache +++ b/templates/angular-request.mustache @@ -19,14 +19,12 @@ if(Object.keys(form).length > 0) { options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; options.transformRequest = {{&className}}.transformRequest; } -$http(options) -.success(function(data, status, headers, config){ +$http(options).then(function(data, status, headers, config){ deferred.resolve(data); if(parameters.$cache !== undefined) { parameters.$cache.put(url, data, parameters.$cacheItemOpts ? parameters.$cacheItemOpts : {}); } -}) -.error(function(data, status, headers, config){ +}, function(data, status, headers, config){ deferred.reject({ status: status, headers: headers, From 330832b04e35133d6cf84754906331615fdc6c8a Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Apr 2016 16:18:23 +1000 Subject: [PATCH 02/61] getTypescriptCode() can generate for Angular using $http --- README.md | 3 ++ lib/codegen.js | 38 +++++++++++++++- lib/typescript.js | 1 + templates/angular-request.mustache | 36 ++++++++------- templates/type.mustache | 8 ++-- templates/typescript-angular-request.mustache | 43 ++++++++++++++++++ templates/typescript-class.mustache | 44 ++++++++++++++++--- templates/typescript-method.mustache | 35 +++++++++++---- templates/typescript-request.mustache | 11 ++--- 9 files changed, 177 insertions(+), 42 deletions(-) create mode 100644 templates/typescript-angular-request.mustache diff --git a/README.md b/README.md index dffa0360..19c57c7e 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,9 @@ In addition to the common options listed below, `getCustomCode()` *requires* a ` lint: type: boolean description: whether or not to run jslint on the generated code + angular: + type: boolean + description: for use with `getTypescriptCode()`. If true, will use $http, otherwise will use superagent. esnext: type: boolean description: passed through to jslint diff --git a/lib/codegen.js b/lib/codegen.js index dd06ade3..035caf24 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -64,10 +64,18 @@ var getViewForSwagger2 = function(opts, type){ moduleName: opts.moduleName, className: opts.className, imports: opts.imports, + angular: opts.angular, domain: (swagger.schemes && swagger.schemes.length > 0 && swagger.host && swagger.basePath) ? swagger.schemes[0] + '://' + swagger.host + swagger.basePath : '', - methods: [] + methods: [], + types: [] }; + _.forEach(swagger.definitions, function(definition, name) { + var type = ts.convertType(definition); + type.name = name.charAt(0).toUpperCase() + name.substring(1); + data.types.push(type); + }); + _.forEach(swagger.paths, function(api, path){ var globalParams = []; /** @@ -110,6 +118,27 @@ var getViewForSwagger2 = function(opts, type){ if(_.isArray(op.parameters)) { params = op.parameters; } + method.hasBody = false; + method.hasForm = false; + + method.tsType = 'void'; + method.hasVoidReturn = true; + if (op.responses) { + _.some(['200', '201'], function(code) { + if (op.responses[code]) { + method.tsType = ts.convertType(op.responses[code]); + if (method.tsType.isRef) { + method.tsType = method.tsType.target.charAt(0).toUpperCase() + method.tsType.target.substring(1); + } else { + method.tsType = method.tsType.tsType; + } + method.hasVoidReturn = false; + return true; + } + }); + } + + params = params.concat(globalParams); _.forEach(params, function(parameter) { // Ignore headers which are injected by proxies & app servers @@ -126,8 +155,10 @@ var getViewForSwagger2 = function(opts, type){ parameter.isSingleton = true; parameter.singleton = parameter.enum[0]; } + parameter.paramType = parameter.in; if(parameter.in === 'body'){ parameter.isBodyParameter = true; + method.hasBody = true; } else if(parameter.in === 'path'){ parameter.isPathParameter = true; } else if(parameter.in === 'query'){ @@ -139,6 +170,7 @@ var getViewForSwagger2 = function(opts, type){ parameter.isHeaderParameter = true; } else if(parameter.in === 'formData'){ parameter.isFormParameter = true; + method.hasForm = true; } parameter.tsType = ts.convertType(parameter); parameter.cardinality = parameter.required ? '' : '?'; @@ -225,7 +257,9 @@ var getCode = function(opts, type) { var templates = __dirname + '/../templates/'; opts.template.class = opts.template.class || fs.readFileSync(templates + type + '-class.mustache', 'utf-8'); opts.template.method = opts.template.method || fs.readFileSync(templates + (type === 'typescript' ? 'typescript-' : '') + 'method.mustache', 'utf-8'); - opts.template.request = opts.template.request || fs.readFileSync(templates + type + '-request.mustache', 'utf-8'); + opts.template.request = opts.template.request || fs.readFileSync(templates + + ((type === 'typescript' && opts.angular) ? 'typescript-angular' : type) + + '-request.mustache', 'utf-8'); if(type === 'typescript') { opts.template.type = fs.readFileSync(templates + 'type.mustache', 'utf-8'); } diff --git a/lib/typescript.js b/lib/typescript.js index 15e1c9ca..a29941f1 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -48,6 +48,7 @@ function convertType(swaggerType) { typespec.isObject = typespec.tsType === 'object'; typespec.isArray = typespec.tsType === 'array'; typespec.isAtomic = _.contains(['string', 'number', 'boolean', 'any'], typespec.tsType); + typespec.description = swaggerType.description; return typespec; diff --git a/templates/angular-request.mustache b/templates/angular-request.mustache index 1c1a71c8..ad4752f4 100644 --- a/templates/angular-request.mustache +++ b/templates/angular-request.mustache @@ -11,24 +11,28 @@ var options = { method: '{{method}}', url: url, params: queryParameters, +{{#hasBody}} data: body, +{{/hasBody}} +{{#hasBody}} + data: form, +{{/hasBody}} headers: headers }; -if(Object.keys(form).length > 0) { - options.data = form; - options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; - options.transformRequest = {{&className}}.transformRequest; -} -$http(options).then(function(data, status, headers, config){ - deferred.resolve(data); +{{! I don't think this is actually needed #hasBody} } +if(typeof(body) === 'object' && !(body.constructor.name === 'Buffer')) { + options.headers['Content-Type'] = 'application/json'; +{ {/hasBody}} +{{#hasForm}} +options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; +options.transformRequest = {{&className}}.transformRequest; +{{/hasForm}} + +$http(options).then(function(response){ + deferred.resolve(response.data); if(parameters.$cache !== undefined) { - parameters.$cache.put(url, data, parameters.$cacheItemOpts ? parameters.$cacheItemOpts : {}); + parameters.$cache.put(url, response.data, parameters.$cacheItemOpts ? parameters.$cacheItemOpts : {}); } -}, function(data, status, headers, config){ - deferred.reject({ - status: status, - headers: headers, - config: config, - body: data - }); -}); +}, deferred.reject); + +return deferred.promise; \ No newline at end of file diff --git a/templates/type.mustache b/templates/type.mustache index 3cccaa6b..c57a41c1 100644 --- a/templates/type.mustache +++ b/templates/type.mustache @@ -4,8 +4,8 @@ <%#isRef%><%target%><%/isRef%><%! %><%#isAtomic%><%tsType%><%/isAtomic%><%! %><%#isObject%>{<%#properties%> -'<%name%>': <%>type%><%/properties%> +<%#description%>/** <%description%> */<%/description%> +'<%name%>': <%>type%>;<%/properties%> }<%/isObject%><%! -%><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>>|<%#elementType%><%>type%><%/elementType%><%/isArray%><%#isBoolean%>boolean<%/isBoolean%> -<%={{ }}=%> -{{/tsType}} \ No newline at end of file +%><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>>|<%#elementType%><%>type%><%/elementType%><%/isArray%><%#isBoolean%>boolean<%/isBoolean%><%! +%><%={{ }}=%>{{/tsType}} \ No newline at end of file diff --git a/templates/typescript-angular-request.mustache b/templates/typescript-angular-request.mustache new file mode 100644 index 00000000..e8bdc109 --- /dev/null +++ b/templates/typescript-angular-request.mustache @@ -0,0 +1,43 @@ +var url = domain + path; +{{#isGET}} +var cached = opts.$cache && opts.$cache.get(url); +if(cached !== undefined && opts.$refresh !== true) { + deferred.resolve(cached); + return deferred.promise; +} +{{/isGET}} +var options = { + timeout: opts.$timeout, + method: '{{method}}', + url: url, + params: queryParameters, +{{#hasBody}} + data: body, +{{/hasBody}} +{{#hasBody}} + data: form, +{{/hasBody}} + headers: headers +}; +{{! I don't think this is actually needed #hasBody} } +if(typeof(body) === 'object' && !(body.constructor.name === 'Buffer')) { + options.headers['Content-Type'] = 'application/json'; +{ {/hasBody}} +{{#hasForm}} +options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; +options.transformRequest = {{&className}}.transformRequest; +{{/hasForm}} + +this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}>){ + {{#hasVoidReturn}} + deferred.resolve(); + {{/hasVoidReturn}} + {{^hasVoidReturn}} + deferred.resolve(response.data); + if(opts.$cache !== undefined) { + opts.$cache.put(url, response.data, opts.$cacheItemOpts ? opts.$cacheItemOpts : {}); + } + {{/hasVoidReturn}} +}, deferred.reject); + +return deferred.promise; \ No newline at end of file diff --git a/templates/typescript-class.mustache b/templates/typescript-class.mustache index 4f2beef7..948cae8b 100644 --- a/templates/typescript-class.mustache +++ b/templates/typescript-class.mustache @@ -1,24 +1,54 @@ {{#imports}} /// {{/imports}} - +{{^angular}} import * as request from "superagent"; +{{/angular}} + +{{#types}} +{{#description}}/** {{description}} */{{/description}} +interface {{name}} {{> type}} + +{{/types}} /** * {{&description}} * @class {{&className}} - * @param {(string)} [domainOrOptions] - The project domain. +{{#angular}} + * @param {ng.IHttpService} $http + * @param {ng.IQService} $q +{{/angular}} + * @param {string} domain - The project domain. +{{#angular}} + * provide using .constant('domain', '//example.com') or .factory('domain', function(){return '//example.com'}) + {{/angular}} */ export default class {{&className}} { +{{#angular}} + static $inject = ['$http', '$q', 'domain']; +{{/angular}} - private domain: string; - - constructor(domain: string) { - this.domain = domain; - } + constructor({{#angular}}private $http: ng.IHttpService, private $q: ng.IQService, {{/angular}}private domain: string) {} {{#methods}} {{> method}} {{/methods}} + +{{#angular}} + private static transformRequest(obj: any): string { + var str = []; + for(var p in obj) { + var val = obj[p]; + if(angular.isArray(val)) { + val.forEach(function(val){ + str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)); + }); + } else { + str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)); + } + } + return str.join('&'); + } +{{/angular}} } diff --git a/templates/typescript-method.mustache b/templates/typescript-method.mustache index 5535b508..857f6186 100644 --- a/templates/typescript-method.mustache +++ b/templates/typescript-method.mustache @@ -13,25 +13,44 @@ {{#parameters}}{{^isSingleton}}'{{&camelCaseName}}'{{&cardinality}}: {{> type}}, {{/isSingleton}}{{/parameters}} $queryParameters?: {} -}): Promise { +}{{#angular}}, opts: { + $timeout?: number; + $refresh?: boolean; + $cache?: { + get:(key: string) => string|Object + put:(key: string, value: string|Object, options?: {}) => void; + }; + $cacheItemOpts?: {}; +} = {} +{{/angular}}): {{#angular}}ng.IPromise<{{&tsType}}{{/angular}}{{^angular}}Promise { let domain = this.domain; let path = '{{&path}}'; + {{#hasBody}} let body; + {{/hasBody}} let queryParameters = {}; let headers = {}; + {{#hasForm}} let form = {}; + {{/hasForm}} +{{#angular}} + let deferred = this.$q.defer(); + +{{/angular}} +{{^angular}} return new Promise(function(resolve, reject) { +{{/angular}} {{#headers}} headers['{{&name}}'] = [{{&value}}]; {{/headers}} {{#parameters}} - {{#required}} - if(parameters['{{&camelCaseName}}'] === undefined){ - reject(new Error('Missing required {{¶mType}} parameter: {{&camelCaseName}}')); + {{! TypeScript should assert required parameters at compile-time #required} } + if(queryParameters['{ {&camelCaseName} } '] === undefined){ + reject(new Error('Missing required { {¶mType} } parameter: { {&camelCaseName} }')); return; } - {{/required}} + { {/required}} {{#isQueryParameter}} {{#isSingleton}} @@ -112,8 +131,8 @@ if(parameters.$queryParameters) { queryParameters[parameterName] = parameter; }); } - {{> request}} - +{{^angular}} }); -}; +{{/angular}} +} diff --git a/templates/typescript-request.mustache b/templates/typescript-request.mustache index 872e4271..4ff484f2 100644 --- a/templates/typescript-request.mustache +++ b/templates/typescript-request.mustache @@ -4,6 +4,7 @@ Object.keys(headers).forEach(key => { req.set(key, headers[key]); }); +{{#hasBody}} if(body) { req.send(body); } @@ -11,11 +12,11 @@ if(body) { if(typeof(body) === 'object' && !(body.constructor.name === 'Buffer')) { req.set('Content-Type', 'application/json'); } - -if(Object.keys(form).length > 0) { - req.type('form'); - req.send(form); -} +{{/hasBody}} +{{#hasForm}} +req.type('form'); +req.send(form); +{{/hasForm}} req.end((error, response) => { if(error) { From 8e974531157724b03a16e262736a019bc994e49f Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Apr 2016 17:01:34 +1000 Subject: [PATCH 03/61] export all interfaces for the module --- templates/typescript-class.mustache | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/templates/typescript-class.mustache b/templates/typescript-class.mustache index 948cae8b..c9335640 100644 --- a/templates/typescript-class.mustache +++ b/templates/typescript-class.mustache @@ -5,9 +5,11 @@ import * as request from "superagent"; {{/angular}} +module {{moduleName}} { + {{#types}} {{#description}}/** {{description}} */{{/description}} -interface {{name}} {{> type}} +export interface {{name}} {{> type}} {{/types}} @@ -52,3 +54,4 @@ export default class {{&className}} { } {{/angular}} } +} \ No newline at end of file From 9e231ccd7379ac6a007753129520695eb4e26e49 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Apr 2016 17:07:53 +1000 Subject: [PATCH 04/61] dropped the `default` export --- templates/typescript-class.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/typescript-class.mustache b/templates/typescript-class.mustache index c9335640..e11c051e 100644 --- a/templates/typescript-class.mustache +++ b/templates/typescript-class.mustache @@ -25,7 +25,7 @@ export interface {{name}} {{> type}} * provide using .constant('domain', '//example.com') or .factory('domain', function(){return '//example.com'}) {{/angular}} */ -export default class {{&className}} { +export class {{&className}} { {{#angular}} static $inject = ['$http', '$q', 'domain']; {{/angular}} From c6d0979de6aa376f55ee6db3d622a999ca8f681f Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Apr 2016 19:51:13 +1000 Subject: [PATCH 05/61] reverted un-related change to README --- README.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/README.md b/README.md index 19c57c7e..05e7f2c3 100644 --- a/README.md +++ b/README.md @@ -133,17 +133,7 @@ methods: description: true if method === 'GET' summary: type: string - description: Provided by the 'description' or 'summary' field in the schema - externalDocs: - type: object - properties: - url: - type: string - description: The URL for the target documentation. Value MUST be in the format of a URL. - required: true - description: - type: string - description: A short description of the target documentation. GitHub-Markdown syntax can be used for rich text representation. + description: Provided by the 'description' field in the schema isSecure: type: boolean description: true if the 'security' is defined for the method in the schema From 8f57b5129f898887563044441eac82b293183b97 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Apr 2016 19:53:57 +1000 Subject: [PATCH 06/61] reverted un-related change --- lib/codegen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codegen.js b/lib/codegen.js index 035caf24..9cee1d15 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -97,7 +97,7 @@ var getViewForSwagger2 = function(opts, type){ methodName: op.operationId ? normalizeName(op.operationId) : getPathToMethodName(opts, m, path), method: m.toUpperCase(), isGET: m.toUpperCase() === 'GET', - summary: op.description || op.summary, + summary: op.description, externalDocs: op.externalDocs, isSecure: swagger.security !== undefined || op.security !== undefined, parameters: [], From 774a49542ce00d36189e4fabac24c2b8e88c5868 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 11:40:20 +1000 Subject: [PATCH 07/61] fixed typo - hasBody->hasForm --- templates/typescript-angular-request.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/typescript-angular-request.mustache b/templates/typescript-angular-request.mustache index e8bdc109..68379cc8 100644 --- a/templates/typescript-angular-request.mustache +++ b/templates/typescript-angular-request.mustache @@ -14,9 +14,9 @@ var options = { {{#hasBody}} data: body, {{/hasBody}} -{{#hasBody}} +{{#hasForm}} data: form, -{{/hasBody}} +{{/hasForm}} headers: headers }; {{! I don't think this is actually needed #hasBody} } From f8ebdce8375bf2d1ab5acfec9c12b3d027ccf9e5 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 17:48:50 +1000 Subject: [PATCH 08/61] updated README to include opts.language and opts.framework --- README.md | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 05e7f2c3..24c50b69 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,12 @@ In addition to the common options listed below, `getCustomCode()` *requires* a ` lint: type: boolean description: whether or not to run jslint on the generated code - angular: - type: boolean - description: for use with `getTypescriptCode()`. If true, will use $http, otherwise will use superagent. + language: + type: string + description: currently only 'typescript' is supported, but could potentially be 'coffeescript', 'es2015'... + framework: + type: string + description: currently only 'angular' is supported, but could potentially be 'react', 'polymer'... esnext: type: boolean description: passed through to jslint @@ -133,7 +136,17 @@ methods: description: true if method === 'GET' summary: type: string - description: Provided by the 'description' field in the schema + description: Provided by the 'description' or 'summary' field in the schema + externalDocs: + type: object + properties: + url: + type: string + description: The URL for the target documentation. Value MUST be in the format of a URL. + required: true + description: + type: string + description: A short description of the target documentation. GitHub-Markdown syntax can be used for rich text representation. isSecure: type: boolean description: true if the 'security' is defined for the method in the schema From c316ada8fd683a4fb0e5738e2b304872b5f552d0 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 17:49:41 +1000 Subject: [PATCH 09/61] added new templates --- templates/typescript-angular-class.mustache | 46 +++++++++ templates/typescript-angular-method.mustache | 103 +++++++++++++++++++ templates/typescript-class.mustache | 37 +------ templates/typescript-method.mustache | 18 +--- 4 files changed, 153 insertions(+), 51 deletions(-) create mode 100644 templates/typescript-angular-class.mustache create mode 100644 templates/typescript-angular-method.mustache diff --git a/templates/typescript-angular-class.mustache b/templates/typescript-angular-class.mustache new file mode 100644 index 00000000..8994bd4b --- /dev/null +++ b/templates/typescript-angular-class.mustache @@ -0,0 +1,46 @@ +{{#imports}} + /// +{{/imports}} + +module {{moduleName}} { + +{{#types}} + {{#description}}/** {{description}} */{{/description}} + export interface {{name}} {{> type}} + +{{/types}} + +/** +* {{&description}} +* @class {{&className}} +* @param {ng.IHttpService} $http +* @param {ng.IQService} $q +* @param {string} domain - The project domain. +* provide using .constant('domain', '//example.com') or .factory('domain', function(){return '//example.com'}) +*/ +export class {{&className}} { + static $inject = ['$http', '$q', 'domain']; + + constructor(private $http: ng.IHttpService, private $q: ng.IQService, private domain: string) {} + +{{#methods}} + {{> method}} + +{{/methods}} + + private static transformRequest(obj: any): string { + var str = []; + for(var p in obj) { + var val = obj[p]; + if(angular.isArray(val)) { + val.forEach(function(val){ + str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)); + }); + } else { + str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)); + } + } + return str.join('&'); + } +} +} diff --git a/templates/typescript-angular-method.mustache b/templates/typescript-angular-method.mustache new file mode 100644 index 00000000..6bcdb136 --- /dev/null +++ b/templates/typescript-angular-method.mustache @@ -0,0 +1,103 @@ +/** +* {{&summary}} +* @method +{{#externalDocs}} +* @see {@link {{&url}}|{{#description}}{{&description}}{{/description}}{{^description}}External docs{{/description}}} +{{/externalDocs}} +* @name {{&className}}#{{&methodName}} +{{#parameters}} + {{^isSingleton}} * @param {{=<% %>=}}{<%&type%>}<%={{ }}=%> {{&camelCaseName}} - {{&description}}{{/isSingleton}} +{{/parameters}} +*/ +{{&methodName}}(parameters: { +{{#parameters}}{{^isSingleton}}'{{&camelCaseName}}'{{&cardinality}}: {{> type}}, +{{/isSingleton}}{{/parameters}} + $queryParameters?: {}, + }, + opts: { + $timeout?: number; + $refresh?: boolean; + $cache?: { + get:(key: string) => string|Object + put:(key: string, value: string|Object, options?: {}) => void; + }; + $cacheItemOpts?: {}; + } = {}): ng.IPromise<{{&tsType}}> { + let domain = this.domain; + let path = '{{&path}}'; + {{#hasBody}} + let body; + {{/hasBody}} + let queryParameters = {}; + let headers = {}; + {{#hasForm}} + let form = {}; + {{/hasForm}} + let deferred = this.$q.defer(); + +{{#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}} + {{^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}} +{{/parameters}} + +if(parameters.$queryParameters) { + Object.keys(parameters.$queryParameters).forEach(function(parameterName){ + var parameter = parameters.$queryParameters[parameterName]; + queryParameters[parameterName] = parameter; + }); +} +{{> request}} +} diff --git a/templates/typescript-class.mustache b/templates/typescript-class.mustache index e11c051e..c8b8fc72 100644 --- a/templates/typescript-class.mustache +++ b/templates/typescript-class.mustache @@ -1,57 +1,26 @@ {{#imports}} /// {{/imports}} -{{^angular}} import * as request from "superagent"; -{{/angular}} module {{moduleName}} { {{#types}} {{#description}}/** {{description}} */{{/description}} -export interface {{name}} {{> type}} +interface {{name}} {{> type}} {{/types}} /** * {{&description}} * @class {{&className}} -{{#angular}} - * @param {ng.IHttpService} $http - * @param {ng.IQService} $q -{{/angular}} * @param {string} domain - The project domain. -{{#angular}} - * provide using .constant('domain', '//example.com') or .factory('domain', function(){return '//example.com'}) - {{/angular}} */ -export class {{&className}} { -{{#angular}} - static $inject = ['$http', '$q', 'domain']; -{{/angular}} - - constructor({{#angular}}private $http: ng.IHttpService, private $q: ng.IQService, {{/angular}}private domain: string) {} +export default class {{&className}} { + constructor(private domain: string) {} {{#methods}} {{> method}} {{/methods}} - -{{#angular}} - private static transformRequest(obj: any): string { - var str = []; - for(var p in obj) { - var val = obj[p]; - if(angular.isArray(val)) { - val.forEach(function(val){ - str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)); - }); - } else { - str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)); - } - } - return str.join('&'); - } -{{/angular}} -} } \ No newline at end of file diff --git a/templates/typescript-method.mustache b/templates/typescript-method.mustache index 98e8a960..0bd15a1d 100644 --- a/templates/typescript-method.mustache +++ b/templates/typescript-method.mustache @@ -13,16 +13,7 @@ {{#parameters}}{{^isSingleton}}'{{&camelCaseName}}'{{&cardinality}}: {{> type}}, {{/isSingleton}}{{/parameters}} $queryParameters?: {} -}{{#angular}}, opts: { - $timeout?: number; - $refresh?: boolean; - $cache?: { - get:(key: string) => string|Object - put:(key: string, value: string|Object, options?: {}) => void; - }; - $cacheItemOpts?: {}; -} = {} -{{/angular}}): {{#angular}}ng.IPromise<{{&tsType}}{{/angular}}{{^angular}}Promise { +}): Promise { let domain = this.domain; let path = '{{&path}}'; {{#hasBody}} @@ -33,13 +24,8 @@ {{#hasForm}} let form = {}; {{/hasForm}} -{{#angular}} - let deferred = this.$q.defer(); -{{/angular}} -{{^angular}} return new Promise(function(resolve, reject) { -{{/angular}} {{#headers}} headers['{{&name}}'] = [{{&value}}]; {{/headers}} @@ -105,7 +91,5 @@ if(parameters.$queryParameters) { }); } {{> request}} -{{^angular}} }); -{{/angular}} } From 6bfe66cf4f89a3f9cda70ab0d84a504c5070a6ba Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 18:00:11 +1000 Subject: [PATCH 10/61] added tests for `selectTemplates` and `locateTemplate` --- tests/utilities.js | 59 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/tests/utilities.js b/tests/utilities.js index 7a3d58e4..16e73454 100644 --- a/tests/utilities.js +++ b/tests/utilities.js @@ -46,6 +46,63 @@ vows.describe('Test Utilities').addBatch({ assert.equal(camelCase('snake_with-kebab'), 'snakeWithKebab'); } } - + }, + 'selectTemplates': { + topic: function(){ + var locateTemplate = CodeGen.__get__('locateTemplate'); + CodeGen.__set__('readTemplate', function(path, language, framework, suffix) { + return locateTemplate(path, language, framework, suffix); + }); + return CodeGen.__get__('selectTemplates'); + }, + 'should be backward-compatible': { + topic: function(selectTemplates) { + return selectTemplates; //_.curry(selectTemplates)({}); + }, + 'with angular': function(selectTemplates) { + var opts = {}; + var dirname = __dirname.replace(/tests$/, 'lib') + '/../templates/'; + selectTemplates(opts, 'angular'); + assert.equal(opts.template.class, dirname + 'angular-class.mustache'); + assert.equal(opts.template.method, dirname + 'method.mustache'); + assert.equal(opts.template.request, dirname + 'angular-request.mustache'); + assert.equal(opts.template.type, undefined); + }, + 'with node': function(selectTemplates) { + var opts = {}; + var dirname = __dirname.replace(/tests$/, 'lib') + '/../templates/'; + selectTemplates(opts, 'node'); + assert.equal(opts.template.class, dirname + 'node-class.mustache'); + assert.equal(opts.template.method, dirname + 'method.mustache'); + assert.equal(opts.template.request, dirname + 'node-request.mustache'); + assert.equal(opts.template.type, undefined); + }, + 'with typescript': function(selectTemplates) { + var opts = {}; + var dirname = __dirname.replace(/tests$/, 'lib') + '/../templates/'; + selectTemplates(opts, 'typescript'); + assert.equal(opts.template.class, dirname + 'typescript-class.mustache'); + assert.equal(opts.template.method, dirname + 'typescript-method.mustache'); + assert.equal(opts.template.request, dirname + 'typescript-request.mustache'); + assert.equal(opts.template.type, dirname + 'type.mustache'); + } + } + }, + 'locateTemplate': { + topic: function(){ + return CodeGen.__get__('locateTemplate'); + }, + 'should find templates for language and framework': function(locateTemplate) { + assert.equal(locateTemplate(__dirname + '/../templates/', 'typescript', 'angular', 'class.mustache'), + __dirname + '/../templates/typescript-angular-class.mustache'); + }, + 'should find templates for language': function(locateTemplate) { + assert.equal(locateTemplate(__dirname + '/../templates/', 'typescript', undefined, 'class.mustache'), + __dirname + '/../templates/typescript-class.mustache'); + }, + 'should find templates for framework': function(locateTemplate) { + assert.equal(locateTemplate(__dirname + '/../templates/', undefined, 'angular', 'class.mustache'), + __dirname + '/../templates/angular-class.mustache'); + } } }).export(module); From 8e42271352b3696a4b7409b62d6b2c3c563ef04c Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 18:01:28 +1000 Subject: [PATCH 11/61] more flexible support for languages and frameworks --- lib/codegen.js | 65 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/lib/codegen.js b/lib/codegen.js index 919cd8cc..9c94808c 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -64,7 +64,6 @@ var getViewForSwagger2 = function(opts, type){ moduleName: opts.moduleName, className: opts.className, imports: opts.imports, - angular: opts.angular, domain: (swagger.schemes && swagger.schemes.length > 0 && swagger.host && swagger.basePath) ? swagger.schemes[0] + '://' + swagger.host + swagger.basePath : '', methods: [], types: [] @@ -248,6 +247,57 @@ var getViewForSwagger1 = function(opts, type){ return data; }; +var fileExists = function(filePath) { + try { + return fs.statSync(filePath).isFile(); + } catch (err) { + return false; + } +}; + +/** + * @param path eg: __dirname + '/../templates/' + * @param language eg: 'typescript', 'coffeescript' + * @param framework eg: 'angular', 'angular2', 'react', 'polymer' + * @param suffix eg: 'class.mustache' + */ +var locateTemplate = function(path, language, framework, suffix) { + if (language && framework && fileExists(path + language + '-' + framework + '-' + suffix)) { + return path + language + '-' + framework + '-' + suffix; + } + if (language && fileExists(path + language + '-' + suffix)) { + return path + language + '-' + suffix; + } + if (framework && fileExists(path + framework + '-' + suffix)) { + return path + framework + '-' + suffix; + } + return path + suffix; +}; + +var readTemplate = function(path, language, framework, suffix) { + return fs.readFileSync(locateTemplate(path, language, framework, suffix), 'utf-8'); +}; + +/** + * @param {{ template?: {}, framework?: string, language?: string }} opts + * @param type - 'typescript', 'angular', 'node' + */ +var selectTemplates = function(opts, type) { + if (!_.isObject(opts.template)) { + opts.template = {}; + } + var templates = __dirname + '/../templates/'; + var language = opts.language || (type === 'typescript' ? type : undefined); + var framework = opts.framework || (type !== 'typescript' ? type : undefined); + + opts.template.class = opts.template.class || readTemplate(templates, language, framework, 'class.mustache'); + opts.template.method = opts.template.method || readTemplate(templates, language, framework, 'method.mustache'); + opts.template.request = opts.template.request || readTemplate(templates, language, framework, 'request.mustache'); + if(type === 'typescript') { + opts.template.type = readTemplate(templates, language, framework, 'type.mustache'); + } +}; + var getCode = function(opts, type) { // For Swagger Specification version 2.0 value of field 'swagger' must be a string '2.0' var data = opts.swagger.swagger === '2.0' ? getViewForSwagger2(opts, type) : getViewForSwagger1(opts, type); @@ -256,18 +306,7 @@ var getCode = function(opts, type) { throw new Error('Unprovided custom template. Please use the following template: template: { class: "...", method: "...", request: "..." }'); } } else { - if (!_.isObject(opts.template)) { - opts.template = {}; - } - var templates = __dirname + '/../templates/'; - opts.template.class = opts.template.class || fs.readFileSync(templates + type + '-class.mustache', 'utf-8'); - opts.template.method = opts.template.method || fs.readFileSync(templates + (type === 'typescript' ? 'typescript-' : '') + 'method.mustache', 'utf-8'); - opts.template.request = opts.template.request || fs.readFileSync(templates + - ((type === 'typescript' && opts.angular) ? 'typescript-angular' : type) + - '-request.mustache', 'utf-8'); - if(type === 'typescript') { - opts.template.type = fs.readFileSync(templates + 'type.mustache', 'utf-8'); - } + selectTemplates(opts, type); } if (opts.mustache) { From f8632016a81c4c04de85f490d32b178c60735a2b Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 18:03:07 +1000 Subject: [PATCH 12/61] restored updated basePath treatment --- lib/codegen.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/codegen.js b/lib/codegen.js index 9c94808c..f7de425e 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -64,7 +64,7 @@ var getViewForSwagger2 = function(opts, type){ moduleName: opts.moduleName, className: opts.className, imports: opts.imports, - domain: (swagger.schemes && swagger.schemes.length > 0 && swagger.host && swagger.basePath) ? swagger.schemes[0] + '://' + swagger.host + swagger.basePath : '', + domain: (swagger.schemes && swagger.schemes.length > 0 && swagger.host && swagger.basePath) ? swagger.schemes[0] + '://' + swagger.host + swagger.basePath.replace(/\/+$/g,'') : '', methods: [], types: [] }; @@ -142,7 +142,6 @@ var getViewForSwagger2 = function(opts, type){ }); } - params = params.concat(globalParams); _.forEach(params, function(parameter) { // Ignore headers which are injected by proxies & app servers From df773a63af68a7e0ceaa598fbe2d321b1ba3af9e Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 18:03:44 +1000 Subject: [PATCH 13/61] restored updated basePath treatment --- lib/codegen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codegen.js b/lib/codegen.js index f7de425e..b1d670a4 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -96,7 +96,7 @@ var getViewForSwagger2 = function(opts, type){ methodName: op.operationId ? normalizeName(op.operationId) : getPathToMethodName(opts, m, path), method: m.toUpperCase(), isGET: m.toUpperCase() === 'GET', - summary: op.description, + summary: op.description || op.summary, externalDocs: op.externalDocs, isSecure: swagger.security !== undefined || op.security !== undefined, parameters: [], From 28b5e9f90327837c167a6d590297f382ffece888 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 18:48:41 +1000 Subject: [PATCH 14/61] hasForm --- templates/angular-request.mustache | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/angular-request.mustache b/templates/angular-request.mustache index ad4752f4..0178fe8c 100644 --- a/templates/angular-request.mustache +++ b/templates/angular-request.mustache @@ -14,9 +14,9 @@ var options = { {{#hasBody}} data: body, {{/hasBody}} -{{#hasBody}} +{{#hasForm}} data: form, -{{/hasBody}} +{{/hasForm}} headers: headers }; {{! I don't think this is actually needed #hasBody} } @@ -35,4 +35,4 @@ $http(options).then(function(response){ } }, deferred.reject); -return deferred.promise; \ No newline at end of file +return deferred.promise; From 06ce4741d65282e7242014e4d43bf13a870599e9 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 18:52:38 +1000 Subject: [PATCH 15/61] New line at EOF --- templates/typescript-class.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/typescript-class.mustache b/templates/typescript-class.mustache index c8b8fc72..9abaaa0d 100644 --- a/templates/typescript-class.mustache +++ b/templates/typescript-class.mustache @@ -23,4 +23,4 @@ export default class {{&className}} { {{> method}} {{/methods}} -} \ No newline at end of file +} From bbf9fcd17867ff3fda213d84cbad02d92ce6a2a4 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Thu, 5 May 2016 10:28:16 +1000 Subject: [PATCH 16/61] updated version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 87869ba7..5b00ba33 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "swagger-js-codegen", "main": "./lib/codegen.js", - "version": "1.4.2", + "version": "1.4.3", "description": "A Swagger codegen for JavaScript", "scripts": { "test": "grunt" From 57d5c9bf3332189dbca9393c7867fb17cc8da385 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Jul 2016 10:56:52 +1000 Subject: [PATCH 17/61] these files were removed from master --- templates/angular-request.mustache | 38 --------------------------- templates/typescript-request.mustache | 29 -------------------- 2 files changed, 67 deletions(-) delete mode 100644 templates/angular-request.mustache delete mode 100644 templates/typescript-request.mustache diff --git a/templates/angular-request.mustache b/templates/angular-request.mustache deleted file mode 100644 index 0178fe8c..00000000 --- a/templates/angular-request.mustache +++ /dev/null @@ -1,38 +0,0 @@ -var url = domain + path; -{{#isGET}} -var cached = parameters.$cache && parameters.$cache.get(url); -if(cached !== undefined && parameters.$refresh !== true) { - deferred.resolve(cached); - return deferred.promise; -} -{{/isGET}} -var options = { - timeout: parameters.$timeout, - method: '{{method}}', - url: url, - params: queryParameters, -{{#hasBody}} - data: body, -{{/hasBody}} -{{#hasForm}} - data: form, -{{/hasForm}} - headers: headers -}; -{{! I don't think this is actually needed #hasBody} } -if(typeof(body) === 'object' && !(body.constructor.name === 'Buffer')) { - options.headers['Content-Type'] = 'application/json'; -{ {/hasBody}} -{{#hasForm}} -options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; -options.transformRequest = {{&className}}.transformRequest; -{{/hasForm}} - -$http(options).then(function(response){ - deferred.resolve(response.data); - if(parameters.$cache !== undefined) { - parameters.$cache.put(url, response.data, parameters.$cacheItemOpts ? parameters.$cacheItemOpts : {}); - } -}, deferred.reject); - -return deferred.promise; diff --git a/templates/typescript-request.mustache b/templates/typescript-request.mustache deleted file mode 100644 index 4ff484f2..00000000 --- a/templates/typescript-request.mustache +++ /dev/null @@ -1,29 +0,0 @@ -let req = request('{{method}}', domain + path) -.query(queryParameters); -Object.keys(headers).forEach(key => { - req.set(key, headers[key]); -}); - -{{#hasBody}} -if(body) { - req.send(body); -} - -if(typeof(body) === 'object' && !(body.constructor.name === 'Buffer')) { - req.set('Content-Type', 'application/json'); -} -{{/hasBody}} -{{#hasForm}} -req.type('form'); -req.send(form); -{{/hasForm}} - -req.end((error, response) => { - if(error) { - reject(error); - } else if(response.status >= 200 && response.status <= 299) { - resolve(response); - } else { - reject(response); - } -}); From 82a37202c9874adcb9eeba3a7cf7e45f1c34c230 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Jul 2016 11:08:52 +1000 Subject: [PATCH 18/61] removed references to `template.request` --- lib/codegen.js | 3 +-- tests/utilities.js | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/codegen.js b/lib/codegen.js index 3d3cc7f3..e4b6dc25 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -298,7 +298,6 @@ var selectTemplates = function(opts, type) { opts.template.class = opts.template.class || readTemplate(templates, language, framework, 'class.mustache'); opts.template.method = opts.template.method || readTemplate(templates, language, framework, 'method.mustache'); - opts.template.request = opts.template.request || readTemplate(templates, language, framework, 'request.mustache'); if(type === 'typescript') { opts.template.type = readTemplate(templates, language, framework, 'type.mustache'); } @@ -309,7 +308,7 @@ var getCode = function(opts, type) { var data = opts.swagger.swagger === '2.0' ? getViewForSwagger2(opts, type) : getViewForSwagger1(opts, type); if (type === 'custom') { if (!_.isObject(opts.template) || !_.isString(opts.template.class) || !_.isString(opts.template.method)) { - throw new Error('Unprovided custom template. Please use the following template: template: { class: "...", method: "...", request: "..." }'); + throw new Error('Unprovided custom template. Please use the following template: template: { class: "...", method: "..." }'); } } else { selectTemplates(opts, type); diff --git a/tests/utilities.js b/tests/utilities.js index 16e73454..188a08d5 100644 --- a/tests/utilities.js +++ b/tests/utilities.js @@ -65,7 +65,6 @@ vows.describe('Test Utilities').addBatch({ selectTemplates(opts, 'angular'); assert.equal(opts.template.class, dirname + 'angular-class.mustache'); assert.equal(opts.template.method, dirname + 'method.mustache'); - assert.equal(opts.template.request, dirname + 'angular-request.mustache'); assert.equal(opts.template.type, undefined); }, 'with node': function(selectTemplates) { @@ -74,7 +73,6 @@ vows.describe('Test Utilities').addBatch({ selectTemplates(opts, 'node'); assert.equal(opts.template.class, dirname + 'node-class.mustache'); assert.equal(opts.template.method, dirname + 'method.mustache'); - assert.equal(opts.template.request, dirname + 'node-request.mustache'); assert.equal(opts.template.type, undefined); }, 'with typescript': function(selectTemplates) { @@ -83,7 +81,6 @@ vows.describe('Test Utilities').addBatch({ selectTemplates(opts, 'typescript'); assert.equal(opts.template.class, dirname + 'typescript-class.mustache'); assert.equal(opts.template.method, dirname + 'typescript-method.mustache'); - assert.equal(opts.template.request, dirname + 'typescript-request.mustache'); assert.equal(opts.template.type, dirname + 'type.mustache'); } } From daa9239543f1f6b95570e570088d4119c87489ec Mon Sep 17 00:00:00 2001 From: adrianwong Date: Mon, 1 Aug 2016 14:56:24 +1000 Subject: [PATCH 19/61] Moved code from "typescript-angular-request.mustache" into "typescript-angular-method.mustache" replacing "{{> request}}" tag. --- templates/typescript-angular-method.mustache | 46 ++++++++++++++++++- templates/typescript-angular-request.mustache | 43 ----------------- 2 files changed, 45 insertions(+), 44 deletions(-) delete mode 100644 templates/typescript-angular-request.mustache diff --git a/templates/typescript-angular-method.mustache b/templates/typescript-angular-method.mustache index 6bcdb136..18512aca 100644 --- a/templates/typescript-angular-method.mustache +++ b/templates/typescript-angular-method.mustache @@ -99,5 +99,49 @@ if(parameters.$queryParameters) { queryParameters[parameterName] = parameter; }); } -{{> request}} + +var url = domain + path; +{{#isGET}} +var cached = opts.$cache && opts.$cache.get(url); +if(cached !== undefined && opts.$refresh !== true) { + deferred.resolve(cached); + return deferred.promise; +} +{{/isGET}} +var options = { + timeout: opts.$timeout, + method: '{{method}}', + url: url, + params: queryParameters, +{{#hasBody}} + data: body, +{{/hasBody}} +{{#hasForm}} + data: form, +{{/hasForm}} + headers: headers +}; +{{! I don't think this is actually needed #hasBody} } +if(typeof(body) === 'object' && !(body.constructor.name === 'Buffer')) { + options.headers['Content-Type'] = 'application/json'; +{ {/hasBody}} +{{#hasForm}} +options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; +options.transformRequest = {{&className}}.transformRequest; +{{/hasForm}} + +this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}>){ + {{#hasVoidReturn}} + deferred.resolve(); + {{/hasVoidReturn}} + {{^hasVoidReturn}} + deferred.resolve(response.data); + if(opts.$cache !== undefined) { + opts.$cache.put(url, response.data, opts.$cacheItemOpts ? opts.$cacheItemOpts : {}); + } + {{/hasVoidReturn}} +}, deferred.reject); + +return deferred.promise; + } diff --git a/templates/typescript-angular-request.mustache b/templates/typescript-angular-request.mustache deleted file mode 100644 index 68379cc8..00000000 --- a/templates/typescript-angular-request.mustache +++ /dev/null @@ -1,43 +0,0 @@ -var url = domain + path; -{{#isGET}} -var cached = opts.$cache && opts.$cache.get(url); -if(cached !== undefined && opts.$refresh !== true) { - deferred.resolve(cached); - return deferred.promise; -} -{{/isGET}} -var options = { - timeout: opts.$timeout, - method: '{{method}}', - url: url, - params: queryParameters, -{{#hasBody}} - data: body, -{{/hasBody}} -{{#hasForm}} - data: form, -{{/hasForm}} - headers: headers -}; -{{! I don't think this is actually needed #hasBody} } -if(typeof(body) === 'object' && !(body.constructor.name === 'Buffer')) { - options.headers['Content-Type'] = 'application/json'; -{ {/hasBody}} -{{#hasForm}} -options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; -options.transformRequest = {{&className}}.transformRequest; -{{/hasForm}} - -this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}>){ - {{#hasVoidReturn}} - deferred.resolve(); - {{/hasVoidReturn}} - {{^hasVoidReturn}} - deferred.resolve(response.data); - if(opts.$cache !== undefined) { - opts.$cache.put(url, response.data, opts.$cacheItemOpts ? opts.$cacheItemOpts : {}); - } - {{/hasVoidReturn}} -}, deferred.reject); - -return deferred.promise; \ No newline at end of file From c5619c924834837dff74cd7d877bf2a532b075dd Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Mon, 22 Aug 2016 14:53:39 +1000 Subject: [PATCH 20/61] restored tests for `selectTemplates`, `locateTemplate` --- package.json | 11 ++++++----- tests/utilities.js | 40 ---------------------------------------- 2 files changed, 6 insertions(+), 45 deletions(-) diff --git a/package.json b/package.json index ee54fddc..5d9854a8 100644 --- a/package.json +++ b/package.json @@ -36,14 +36,15 @@ "mustache": "^2.0.0" }, "devDependencies": { + "final-fs": "~1.6.0", "grunt": "~0.4.4", "grunt-contrib-jshint": "~0.9.2", + "grunt-jsonlint": "~1.0.4", "grunt-vows": "~0.4.1", - "q": "~1.0.1", - "final-fs": "~1.6.0", "matchdep": "~0.3.0", - "vows": "~0.7.0", - "grunt-jsonlint": "~1.0.4", - "request": "~2.40.0" + "q": "~1.0.1", + "request": "~2.40.0", + "rewire": "^2.5.2", + "vows": "~0.7.0" } } diff --git a/tests/utilities.js b/tests/utilities.js index 188a08d5..23b57c09 100644 --- a/tests/utilities.js +++ b/tests/utilities.js @@ -3,50 +3,10 @@ var assert = require('assert'); var rewire = require('rewire'); var vows = require('vows'); -var _ = require('lodash'); var CodeGen = rewire('../lib/codegen.js'); vows.describe('Test Utilities').addBatch({ - 'camelCase': { - topic: function(){ - return CodeGen.__get__('camelCase'); - }, - 'by default': { - topic: function(camelCase) { - return _.curry(camelCase)({}); - }, - 'should leave camelCase as camelCase': function(camelCase) { - assert.equal(camelCase('alreadyCamel'), 'alreadyCamel'); - }, - 'should convert kebab-case to camelCase': function(camelCase) { - assert.equal(camelCase('kebab-case'), 'kebabCase'); - assert.equal(camelCase('double-kebab-case'), 'doubleKebabCase'); - }, - 'should not convert snake_case to camelCase': function(camelCase) { - assert.equal(camelCase('snake_case'), 'snake_case'); - assert.equal(camelCase('double_snake_case'), 'double_snake_case'); - assert.equal(camelCase('snake_with-kebab'), 'snake_withKebab'); - } - }, - 'when convertSnakeCase is true': { - topic: function(camelCase) { - return _.curry(camelCase)({convertSnakeCase: true}); - }, - 'should leave camelCase as camelCase': function(camelCase) { - assert.equal(camelCase('alreadyCamel'), 'alreadyCamel'); - }, - 'should convert kebab-case to camelCase': function(camelCase) { - assert.equal(camelCase('kebab-case'), 'kebabCase'); - assert.equal(camelCase('double-kebab-case'), 'doubleKebabCase'); - }, - 'should convert snake_case to camelCase': function(camelCase) { - assert.equal(camelCase('snake_case'), 'snakeCase'); - assert.equal(camelCase('double_snake_case'), 'doubleSnakeCase'); - assert.equal(camelCase('snake_with-kebab'), 'snakeWithKebab'); - } - } - }, 'selectTemplates': { topic: function(){ var locateTemplate = CodeGen.__get__('locateTemplate'); From 4be38ae11031ecc01bcf41bb1857b4330cf7b1b2 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Mon, 22 Aug 2016 15:56:24 +1000 Subject: [PATCH 21/61] added support for optional fields --- lib/typescript.js | 4 ++-- templates/type.mustache | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/typescript.js b/lib/typescript.js index 07a72fff..b50e847c 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -14,7 +14,6 @@ var _ = require('lodash'); function convertType(swaggerType) { var typespec = {}; - if (swaggerType.hasOwnProperty('schema')) { return convertType(swaggerType.schema); } else if (_.isString(swaggerType.$ref)) { @@ -32,10 +31,10 @@ function convertType(swaggerType) { } else if (swaggerType.type === 'object') { typespec.tsType = 'object'; typespec.properties = []; - _.forEach(swaggerType.properties, function (propertyType, propertyName) { var property = convertType(propertyType); property.name = propertyName; + property.isOptional = !(swaggerType.required && _.includes(swaggerType.required, propertyName)); typespec.properties.push(property); }); } else { @@ -48,6 +47,7 @@ function convertType(swaggerType) { typespec.isObject = typespec.tsType === 'object'; typespec.isArray = typespec.tsType === 'array'; typespec.isAtomic = _.includes(['string', 'number', 'boolean', 'any'], typespec.tsType); + typespec.isOptional = !swaggerType.required; typespec.description = swaggerType.description; return typespec; diff --git a/templates/type.mustache b/templates/type.mustache index c57a41c1..3cf3769d 100644 --- a/templates/type.mustache +++ b/templates/type.mustache @@ -5,7 +5,7 @@ %><%#isAtomic%><%tsType%><%/isAtomic%><%! %><%#isObject%>{<%#properties%> <%#description%>/** <%description%> */<%/description%> -'<%name%>': <%>type%>;<%/properties%> +<%name%><%#isOptional%>?<%/isOptional%>: <%>type%>;<%/properties%> }<%/isObject%><%! %><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>>|<%#elementType%><%>type%><%/elementType%><%/isArray%><%#isBoolean%>boolean<%/isBoolean%><%! %><%={{ }}=%>{{/tsType}} \ No newline at end of file From d93694236f3bf1e584b41a1361e10d17a5d3787d Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Mon, 22 Aug 2016 16:42:00 +1000 Subject: [PATCH 22/61] default response is not always 200/201 - fallback to "any " --- lib/typescript.js | 1 - templates/typescript-angular-method.mustache | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/typescript.js b/lib/typescript.js index b50e847c..5ab6bae9 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -51,7 +51,6 @@ function convertType(swaggerType) { typespec.description = swaggerType.description; return typespec; - } module.exports.convertType = convertType; diff --git a/templates/typescript-angular-method.mustache b/templates/typescript-angular-method.mustache index 18512aca..451173d8 100644 --- a/templates/typescript-angular-method.mustache +++ b/templates/typescript-angular-method.mustache @@ -22,7 +22,7 @@ put:(key: string, value: string|Object, options?: {}) => void; }; $cacheItemOpts?: {}; - } = {}): ng.IPromise<{{&tsType}}> { + } = {}): ng.IPromise<{{&tsType}}|any> { let domain = this.domain; let path = '{{&path}}'; {{#hasBody}} @@ -130,7 +130,7 @@ options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; options.transformRequest = {{&className}}.transformRequest; {{/hasForm}} -this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}>){ +this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}|any>){ {{#hasVoidReturn}} deferred.resolve(); {{/hasVoidReturn}} From 9521a68217015c8981837637dd1d04a58ee2c5f4 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Thu, 1 Dec 2016 15:28:12 +1100 Subject: [PATCH 23/61] reject responses with status codes >= 400 --- templates/typescript-angular-method.mustache | 22 ++++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/templates/typescript-angular-method.mustache b/templates/typescript-angular-method.mustache index 451173d8..de9663da 100644 --- a/templates/typescript-angular-method.mustache +++ b/templates/typescript-angular-method.mustache @@ -10,7 +10,7 @@ {{/parameters}} */ {{&methodName}}(parameters: { -{{#parameters}}{{^isSingleton}}'{{&camelCaseName}}'{{&cardinality}}: {{> type}}, +{{#parameters}}{{^isSingleton}}{{&camelCaseName}}{{&cardinality}}: {{> type}}, {{/isSingleton}}{{/parameters}} $queryParameters?: {}, }, @@ -131,15 +131,19 @@ options.transformRequest = {{&className}}.transformRequest; {{/hasForm}} this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}|any>){ - {{#hasVoidReturn}} - deferred.resolve(); - {{/hasVoidReturn}} - {{^hasVoidReturn}} - deferred.resolve(response.data); - if(opts.$cache !== undefined) { - opts.$cache.put(url, response.data, opts.$cacheItemOpts ? opts.$cacheItemOpts : {}); + if(response.status >= 400) { + deferred.reject(response); + } else { + {{#hasVoidReturn}} + deferred.resolve(); + {{/hasVoidReturn}} + {{^hasVoidReturn}} + deferred.resolve(response.data); + if(opts.$cache !== undefined) { + opts.$cache.put(url, response.data, opts.$cacheItemOpts ? opts.$cacheItemOpts : {}); + } + {{/hasVoidReturn}} } - {{/hasVoidReturn}} }, deferred.reject); return deferred.promise; From 6c878a5443f288eadc42caae90c0b5a81e2aa261 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Thu, 1 Dec 2016 15:31:05 +1100 Subject: [PATCH 24/61] don't generate code for OPTIONS requests --- lib/codegen.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codegen.js b/lib/codegen.js index e0acc355..ed6256f9 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -179,6 +179,8 @@ var getViewForSwagger1 = function(opts, type){ }; swagger.apis.forEach(function(api){ api.operations.forEach(function(op){ + if (op.method == 'OPTIONS') return; + var method = { path: api.path, className: opts.className, From 5e3728aededc4e9fd78d8ea5c3dd98d7e22ed615 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Thu, 1 Dec 2016 16:00:50 +1100 Subject: [PATCH 25/61] don't generate code for OPTIONS requests --- lib/codegen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codegen.js b/lib/codegen.js index ed6256f9..03cd0989 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -63,7 +63,7 @@ var getViewForSwagger2 = function(opts, type){ } }); _.forEach(api, function(op, m){ - if(authorizedMethods.indexOf(m.toUpperCase()) === -1) { + if(authorizedMethods.indexOf(m.toUpperCase()) === -1 || m.toUpperCase() == 'OPTIONS') { return; } var method = { From 5f135b93de3fe61a0a2ef632a466f0b1b6a29dce Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Fri, 3 Feb 2017 15:44:23 +1100 Subject: [PATCH 26/61] fix up after update from master --- lib/codegen.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/codegen.js b/lib/codegen.js index d0cc2a18..fe51701d 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -48,7 +48,7 @@ var getViewForSwagger2 = function(opts, type){ _.forEach(swagger.definitions, function(definition, name) { var type = ts.convertType(definition); type.name = name.charAt(0).toUpperCase() + name.substring(1); - data.types.push(type); + data.definitions.push(type); }); _.forEach(swagger.paths, function(api, path){ @@ -166,13 +166,6 @@ var getViewForSwagger2 = function(opts, type){ }); }); - _.forEach(swagger.definitions, function(definition, name){ - data.definitions.push({ - name: name, - tsType: ts.convertType(definition) - }); - }); - return data; }; From 3b98e57c166c186b8dab8fa52860e24f63142af5 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Fri, 3 Feb 2017 15:45:08 +1100 Subject: [PATCH 27/61] Array is not implicity Array|Element --- templates/type.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/type.mustache b/templates/type.mustache index ae63c337..595d7135 100644 --- a/templates/type.mustache +++ b/templates/type.mustache @@ -6,5 +6,5 @@ %><%#isObject%>{<%#properties%> <%#description%>/** <%description%> */<%/description%> <%name%><%#isOptional%>?<%/isOptional%>: <%>type%>;<%/properties%> -}<%/isObject%><%!%><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>>|<%#elementType%><%>type%><%/elementType%><%/isArray%><%#isBoolean%>boolean<%/isBoolean%><%! +}<%/isObject%><%!%><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>><%/isArray%><%#isBoolean%>boolean<%/isBoolean%><%! %><%={{ }}=%>{{/tsType}} From a41d233d0e977dca2383a2391602c78d311bc1c7 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Fri, 3 Feb 2017 15:46:34 +1100 Subject: [PATCH 28/61] treat `type:array` definitions as `type name = ...` --- templates/typescript-angular-class.mustache | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/templates/typescript-angular-class.mustache b/templates/typescript-angular-class.mustache index 8994bd4b..7652b94b 100644 --- a/templates/typescript-angular-class.mustache +++ b/templates/typescript-angular-class.mustache @@ -4,11 +4,12 @@ module {{moduleName}} { -{{#types}} +{{#definitions}} {{#description}}/** {{description}} */{{/description}} - export interface {{name}} {{> type}} + {{#isObject}}export interface {{name}} {{> type}}{{/isObject}} + {{#isArray}}export type {{name}} = {{> type}};{{/isArray}} -{{/types}} +{{/definitions}} /** * {{&description}} From a4751ed2d2645a8028f8ac7d774e8621ec14f1a2 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Fri, 3 Feb 2017 15:47:02 +1100 Subject: [PATCH 29/61] renamed `types` as `definitions` --- templates/typescript-class.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/typescript-class.mustache b/templates/typescript-class.mustache index 4b001b90..bdf1988a 100644 --- a/templates/typescript-class.mustache +++ b/templates/typescript-class.mustache @@ -11,11 +11,11 @@ type {{&name}} = {{#tsType}}{{> type}}{{/tsType}}; module {{moduleName}} { -{{#types}} +{{#definitions}} {{#description}}/** {{description}} */{{/description}} interface {{name}} {{> type}} -{{/types}} +{{/definitions}} /** * {{&description}} From 6ca3f7f2f2c43e23f2e10dfe242faca3616468a3 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Apr 2016 16:18:23 +1000 Subject: [PATCH 30/61] getTypescriptCode() can generate for Angular using $http --- README.md | 3 ++ lib/codegen.js | 41 ++++++++++++++---- lib/typescript.js | 3 ++ templates/type.mustache | 16 +++---- templates/typescript-angular-request.mustache | 43 +++++++++++++++++++ templates/typescript-class.mustache | 4 +- templates/typescript-method.mustache | 2 +- 7 files changed, 93 insertions(+), 19 deletions(-) create mode 100644 templates/typescript-angular-request.mustache diff --git a/README.md b/README.md index bef96642..63ddd14f 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,9 @@ In addition to the common options listed below, `getCustomCode()` *requires* a ` lint: type: boolean description: whether or not to run jslint on the generated code + angular: + type: boolean + description: for use with `getTypescriptCode()`. If true, will use $http, otherwise will use superagent. esnext: type: boolean description: passed through to jslint diff --git a/lib/codegen.js b/lib/codegen.js index 65b356d1..95bef608 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -93,9 +93,32 @@ var getViewForSwagger2 = function(opts, type){ if(_.isArray(op.parameters)) { params = op.parameters; } + + method.hasBody = false; + method.hasForm = false; + method.tsType = 'void'; + method.hasVoidReturn = true; + + if (op.responses) { + _.some(['200', '201'], function(code) { + if (op.responses[code]) { + method.tsType = ts.convertType(op.responses[code]); + if (method.tsType.isRef) { + method.tsType = method.tsType.target.charAt(0).toUpperCase() + method.tsType.target.substring(1); + } else { + method.tsType = method.tsType.tsType; + } + if (method.tsType != 'any') { + method.hasVoidReturn = false; + } + return true; + } + }); + } + params = params.concat(globalParams); _.forEach(params, function(parameter) { - //Ignore parameters which contain the x-exclude-from-bindings extension + // Ignore parameters which contain the x-exclude-from-bindings extension if(parameter['x-exclude-from-bindings'] === true) { return; } @@ -114,8 +137,10 @@ var getViewForSwagger2 = function(opts, type){ parameter.isSingleton = true; parameter.singleton = parameter.enum[0]; } + parameter.paramType = parameter.in; if(parameter.in === 'body'){ parameter.isBodyParameter = true; + method.hasBody = true; } else if(parameter.in === 'path'){ parameter.isPathParameter = true; } else if(parameter.in === 'query'){ @@ -128,6 +153,7 @@ var getViewForSwagger2 = function(opts, type){ parameter.isHeaderParameter = true; } else if(parameter.in === 'formData'){ parameter.isFormParameter = true; + method.hasForm = true; } parameter.tsType = ts.convertType(parameter); parameter.cardinality = parameter.required ? '' : '?'; @@ -137,11 +163,10 @@ var getViewForSwagger2 = function(opts, type){ }); }); - _.forEach(swagger.definitions, function(definition, name){ - data.definitions.push({ - name: name, - tsType: ts.convertType(definition) - }); + _.forEach(swagger.definitions, function(definition, name) { + var type = ts.convertType(definition); + type.name = name.charAt(0).toUpperCase() + name.substring(1); + data.types.push(type); }); return data; @@ -224,7 +249,7 @@ var getCode = function(opts, type) { var templates = __dirname + '/../templates/'; opts.template.class = opts.template.class || fs.readFileSync(templates + type + '-class.mustache', 'utf-8'); opts.template.method = opts.template.method || fs.readFileSync(templates + (type === 'typescript' ? 'typescript-' : '') + 'method.mustache', 'utf-8'); - if(type === 'typescript') { + if (type === 'typescript') { opts.template.type = opts.template.type || fs.readFileSync(templates + 'type.mustache', 'utf-8'); } } @@ -247,7 +272,7 @@ var getCode = function(opts, type) { lintOptions.esnext = true; } - if(type === 'typescript') { + if (type === 'typescript') { opts.lint = false; } diff --git a/lib/typescript.js b/lib/typescript.js index b33070c4..e07111dd 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -43,6 +43,7 @@ function convertType(swaggerType) { }); } else { // type unknown or unsupported... just map to 'any'... + // TODO: probably void typespec.tsType = 'any'; } @@ -51,6 +52,8 @@ function convertType(swaggerType) { typespec.isObject = typespec.tsType === 'object'; typespec.isArray = typespec.tsType === 'array'; typespec.isAtomic = typespec.isAtomic || _.includes(['string', 'number', 'boolean', 'any'], typespec.tsType); + typespec.isAtomic = _.contains(['string', 'number', 'boolean', 'any'], typespec.tsType); + typespec.description = swaggerType.description; return typespec; diff --git a/templates/type.mustache b/templates/type.mustache index d8f2518d..ada7c0cf 100644 --- a/templates/type.mustache +++ b/templates/type.mustache @@ -1,11 +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%>': <%>type%><%/properties%> -}<%/isObject%><%! -%><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>>|<%#elementType%><%>type%><%/elementType%><%/isArray%> -<%={{ }}=%> + {{=<% %>=}} + <%#isRef%><%target%><%/isRef%><%! + %><%#isAtomic%><%&tsType%><%/isAtomic%><%! + %><%#isObject%>{<%#properties%> + '<%name%>': <%>type%><%/properties%> + }<%/isObject%><%! + %><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>>|<%#elementType%><%>type%><%/elementType%><%/isArray%> + <%={{ }}=%> {{/tsType}} \ No newline at end of file diff --git a/templates/typescript-angular-request.mustache b/templates/typescript-angular-request.mustache new file mode 100644 index 00000000..e8bdc109 --- /dev/null +++ b/templates/typescript-angular-request.mustache @@ -0,0 +1,43 @@ +var url = domain + path; +{{#isGET}} +var cached = opts.$cache && opts.$cache.get(url); +if(cached !== undefined && opts.$refresh !== true) { + deferred.resolve(cached); + return deferred.promise; +} +{{/isGET}} +var options = { + timeout: opts.$timeout, + method: '{{method}}', + url: url, + params: queryParameters, +{{#hasBody}} + data: body, +{{/hasBody}} +{{#hasBody}} + data: form, +{{/hasBody}} + headers: headers +}; +{{! I don't think this is actually needed #hasBody} } +if(typeof(body) === 'object' && !(body.constructor.name === 'Buffer')) { + options.headers['Content-Type'] = 'application/json'; +{ {/hasBody}} +{{#hasForm}} +options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; +options.transformRequest = {{&className}}.transformRequest; +{{/hasForm}} + +this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}>){ + {{#hasVoidReturn}} + deferred.resolve(); + {{/hasVoidReturn}} + {{^hasVoidReturn}} + deferred.resolve(response.data); + if(opts.$cache !== undefined) { + opts.$cache.put(url, response.data, opts.$cacheItemOpts ? opts.$cacheItemOpts : {}); + } + {{/hasVoidReturn}} +}, deferred.reject); + +return deferred.promise; \ No newline at end of file diff --git a/templates/typescript-class.mustache b/templates/typescript-class.mustache index d4f81ddf..600d10c7 100644 --- a/templates/typescript-class.mustache +++ b/templates/typescript-class.mustache @@ -13,7 +13,7 @@ type {{&name}} = {{#tsType}}{{> type}}{{/tsType}}; /** * {{&description}} * @class {{&className}} - * @param {(string)} [domainOrOptions] - The project domain. + * @param {string} domain - The project domain. */ export default class {{&className}} { @@ -68,4 +68,4 @@ export default class {{&className}} { {{> method}} {{/methods}} -} +} \ No newline at end of file diff --git a/templates/typescript-method.mustache b/templates/typescript-method.mustache index 45bf93d6..49832902 100644 --- a/templates/typescript-method.mustache +++ b/templates/typescript-method.mustache @@ -161,4 +161,4 @@ if(parameters.$queryParameters) { request('{{method}}', domain + path, body, headers, queryParameters, form, reject, resolve, errorHandlers); }); -}; +} \ No newline at end of file From c47beee642f5190277f2222c938190c2e2945fe6 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Apr 2016 19:51:13 +1000 Subject: [PATCH 31/61] reverted un-related change to README --- README.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/README.md b/README.md index 63ddd14f..67867baa 100644 --- a/README.md +++ b/README.md @@ -133,17 +133,7 @@ methods: description: true if method === 'GET' summary: type: string - description: Provided by the 'description' or 'summary' field in the schema - externalDocs: - type: object - properties: - url: - type: string - description: The URL for the target documentation. Value MUST be in the format of a URL. - required: true - description: - type: string - description: A short description of the target documentation. GitHub-Markdown syntax can be used for rich text representation. + description: Provided by the 'description' field in the schema isSecure: type: boolean description: true if the 'security' is defined for the method in the schema From 9974ba18217751c0a079fdf65d37fdd307f9e25f Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Apr 2016 19:53:57 +1000 Subject: [PATCH 32/61] reverted un-related change --- lib/codegen.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/codegen.js b/lib/codegen.js index 95bef608..1042c100 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -74,7 +74,7 @@ var getViewForSwagger2 = function(opts, type){ headers: [] }; - if(op.produces) { + if (op.produces) { var headers = []; headers.value = []; @@ -85,12 +85,12 @@ var getViewForSwagger2 = function(opts, type){ } var consumes = op.consumes || swagger.consumes; - if(consumes) { + if (consumes) { method.headers.push({name: 'Content-Type', value: '\'' + consumes + '\'' }); } var params = []; - if(_.isArray(op.parameters)) { + if (_.isArray(op.parameters)) { params = op.parameters; } From 82591540ecbbe1586d5aba72170440913e432fe1 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 11:40:20 +1000 Subject: [PATCH 33/61] fixed typo - hasBody->hasForm --- templates/typescript-angular-request.mustache | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/typescript-angular-request.mustache b/templates/typescript-angular-request.mustache index e8bdc109..68379cc8 100644 --- a/templates/typescript-angular-request.mustache +++ b/templates/typescript-angular-request.mustache @@ -14,9 +14,9 @@ var options = { {{#hasBody}} data: body, {{/hasBody}} -{{#hasBody}} +{{#hasForm}} data: form, -{{/hasBody}} +{{/hasForm}} headers: headers }; {{! I don't think this is actually needed #hasBody} } From ba8b3a0f590e2f358de79fa033235ecb24132729 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 17:48:50 +1000 Subject: [PATCH 34/61] updated README to include opts.language and opts.framework --- README.md | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 67867baa..af85abd3 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,12 @@ In addition to the common options listed below, `getCustomCode()` *requires* a ` lint: type: boolean description: whether or not to run jslint on the generated code - angular: - type: boolean - description: for use with `getTypescriptCode()`. If true, will use $http, otherwise will use superagent. + language: + type: string + description: currently only 'typescript' is supported, but could potentially be 'coffeescript', 'es2015'... + framework: + type: string + description: currently only 'angular' is supported, but could potentially be 'react', 'polymer'... esnext: type: boolean description: passed through to jslint @@ -133,7 +136,17 @@ methods: description: true if method === 'GET' summary: type: string - description: Provided by the 'description' field in the schema + description: Provided by the 'description' or 'summary' field in the schema + externalDocs: + type: object + properties: + url: + type: string + description: The URL for the target documentation. Value MUST be in the format of a URL. + required: true + description: + type: string + description: A short description of the target documentation. GitHub-Markdown syntax can be used for rich text representation. isSecure: type: boolean description: true if the 'security' is defined for the method in the schema From 582b84ce0cf050a588598b558d4f6dc419036f07 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 17:49:41 +1000 Subject: [PATCH 35/61] added new templates --- templates/typescript-angular-class.mustache | 46 +++++++++ templates/typescript-angular-method.mustache | 103 +++++++++++++++++++ templates/typescript-method.mustache | 14 +-- 3 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 templates/typescript-angular-class.mustache create mode 100644 templates/typescript-angular-method.mustache diff --git a/templates/typescript-angular-class.mustache b/templates/typescript-angular-class.mustache new file mode 100644 index 00000000..8994bd4b --- /dev/null +++ b/templates/typescript-angular-class.mustache @@ -0,0 +1,46 @@ +{{#imports}} + /// +{{/imports}} + +module {{moduleName}} { + +{{#types}} + {{#description}}/** {{description}} */{{/description}} + export interface {{name}} {{> type}} + +{{/types}} + +/** +* {{&description}} +* @class {{&className}} +* @param {ng.IHttpService} $http +* @param {ng.IQService} $q +* @param {string} domain - The project domain. +* provide using .constant('domain', '//example.com') or .factory('domain', function(){return '//example.com'}) +*/ +export class {{&className}} { + static $inject = ['$http', '$q', 'domain']; + + constructor(private $http: ng.IHttpService, private $q: ng.IQService, private domain: string) {} + +{{#methods}} + {{> method}} + +{{/methods}} + + private static transformRequest(obj: any): string { + var str = []; + for(var p in obj) { + var val = obj[p]; + if(angular.isArray(val)) { + val.forEach(function(val){ + str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)); + }); + } else { + str.push(encodeURIComponent(p) + '=' + encodeURIComponent(val)); + } + } + return str.join('&'); + } +} +} diff --git a/templates/typescript-angular-method.mustache b/templates/typescript-angular-method.mustache new file mode 100644 index 00000000..6bcdb136 --- /dev/null +++ b/templates/typescript-angular-method.mustache @@ -0,0 +1,103 @@ +/** +* {{&summary}} +* @method +{{#externalDocs}} +* @see {@link {{&url}}|{{#description}}{{&description}}{{/description}}{{^description}}External docs{{/description}}} +{{/externalDocs}} +* @name {{&className}}#{{&methodName}} +{{#parameters}} + {{^isSingleton}} * @param {{=<% %>=}}{<%&type%>}<%={{ }}=%> {{&camelCaseName}} - {{&description}}{{/isSingleton}} +{{/parameters}} +*/ +{{&methodName}}(parameters: { +{{#parameters}}{{^isSingleton}}'{{&camelCaseName}}'{{&cardinality}}: {{> type}}, +{{/isSingleton}}{{/parameters}} + $queryParameters?: {}, + }, + opts: { + $timeout?: number; + $refresh?: boolean; + $cache?: { + get:(key: string) => string|Object + put:(key: string, value: string|Object, options?: {}) => void; + }; + $cacheItemOpts?: {}; + } = {}): ng.IPromise<{{&tsType}}> { + let domain = this.domain; + let path = '{{&path}}'; + {{#hasBody}} + let body; + {{/hasBody}} + let queryParameters = {}; + let headers = {}; + {{#hasForm}} + let form = {}; + {{/hasForm}} + let deferred = this.$q.defer(); + +{{#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}} + {{^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}} +{{/parameters}} + +if(parameters.$queryParameters) { + Object.keys(parameters.$queryParameters).forEach(function(parameterName){ + var parameter = parameters.$queryParameters[parameterName]; + queryParameters[parameterName] = parameter; + }); +} +{{> request}} +} diff --git a/templates/typescript-method.mustache b/templates/typescript-method.mustache index 49832902..c0f90139 100644 --- a/templates/typescript-method.mustache +++ b/templates/typescript-method.mustache @@ -144,12 +144,12 @@ $domain?: string {{/parameters}} -if(parameters.$queryParameters) { - Object.keys(parameters.$queryParameters).forEach(function(parameterName){ - var parameter = parameters.$queryParameters[parameterName]; - queryParameters[parameterName] = parameter; - }); -} + if(parameters.$queryParameters) { + Object.keys(parameters.$queryParameters).forEach(function(parameterName){ + var parameter = parameters.$queryParameters[parameterName]; + queryParameters[parameterName] = parameter; + }); + } {{^isBodyParameter}} {{#isPOST}} @@ -161,4 +161,4 @@ if(parameters.$queryParameters) { request('{{method}}', domain + path, body, headers, queryParameters, form, reject, resolve, errorHandlers); }); -} \ No newline at end of file +} From 7e2b4768671cd8450a5b4236795343b7552fdd09 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 18:01:28 +1000 Subject: [PATCH 36/61] more flexible support for languages and frameworks --- lib/codegen.js | 60 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/lib/codegen.js b/lib/codegen.js index 1042c100..cc86915e 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -235,6 +235,56 @@ var getViewForSwagger1 = function(opts, type){ return data; }; +var fileExists = function(filePath) { + try { + return fs.statSync(filePath).isFile(); + } catch (err) { + return false; + } +}; + +/** + * @param path eg: __dirname + '/../templates/' + * @param language eg: 'typescript', 'coffeescript' + * @param framework eg: 'angular', 'angular2', 'react', 'polymer' + * @param suffix eg: 'class.mustache' + */ +var locateTemplate = function(path, language, framework, suffix) { + if (language && framework && fileExists(path + language + '-' + framework + '-' + suffix)) { + return path + language + '-' + framework + '-' + suffix; + } + if (language && fileExists(path + language + '-' + suffix)) { + return path + language + '-' + suffix; + } + if (framework && fileExists(path + framework + '-' + suffix)) { + return path + framework + '-' + suffix; + } + return path + suffix; +}; + +var readTemplate = function(path, language, framework, suffix) { + return fs.readFileSync(locateTemplate(path, language, framework, suffix), 'utf-8'); +}; + +/** + * @param {{ template?: {}, framework?: string, language?: string }} opts + * @param type - 'typescript', 'angular', 'node' + */ +var selectTemplates = function(opts, type) { + if (!_.isObject(opts.template)) { + opts.template = {}; + } + var templates = __dirname + '/../templates/'; + var language = opts.language || (type === 'typescript' ? type : undefined); + var framework = opts.framework || (type !== 'typescript' ? type : undefined); + + opts.template.class = opts.template.class || readTemplate(templates, language, framework, 'class.mustache'); + opts.template.method = opts.template.method || readTemplate(templates, language, framework, 'method.mustache'); + if(type === 'typescript') { + opts.template.type = readTemplate(templates, language, framework, 'type.mustache'); + } +}; + var getCode = function(opts, type) { // For Swagger Specification version 2.0 value of field 'swagger' must be a string '2.0' var data = opts.swagger.swagger === '2.0' ? getViewForSwagger2(opts, type) : getViewForSwagger1(opts, type); @@ -243,15 +293,7 @@ var getCode = function(opts, type) { throw new Error('Unprovided custom template. Please use the following template: template: { class: "...", method: "...", request: "..." }'); } } else { - if (!_.isObject(opts.template)) { - opts.template = {}; - } - var templates = __dirname + '/../templates/'; - opts.template.class = opts.template.class || fs.readFileSync(templates + type + '-class.mustache', 'utf-8'); - opts.template.method = opts.template.method || fs.readFileSync(templates + (type === 'typescript' ? 'typescript-' : '') + 'method.mustache', 'utf-8'); - if (type === 'typescript') { - opts.template.type = opts.template.type || fs.readFileSync(templates + 'type.mustache', 'utf-8'); - } + selectTemplates(opts, type); } if (opts.mustache) { From 88d319c5edf831d47a628686c918d881b2dc3841 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 18:48:41 +1000 Subject: [PATCH 37/61] hasForm --- templates/typescript-angular-request.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/typescript-angular-request.mustache b/templates/typescript-angular-request.mustache index 68379cc8..7dffbc2b 100644 --- a/templates/typescript-angular-request.mustache +++ b/templates/typescript-angular-request.mustache @@ -40,4 +40,4 @@ this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType {{/hasVoidReturn}} }, deferred.reject); -return deferred.promise; \ No newline at end of file +return deferred.promise; From 49551ca590ee8f8fbfc7f807e0892737802a1a8d Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 4 May 2016 18:52:38 +1000 Subject: [PATCH 38/61] New line at EOF --- templates/typescript-class.mustache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/typescript-class.mustache b/templates/typescript-class.mustache index 600d10c7..b70f4a74 100644 --- a/templates/typescript-class.mustache +++ b/templates/typescript-class.mustache @@ -68,4 +68,4 @@ export default class {{&className}} { {{> method}} {{/methods}} -} \ No newline at end of file +} From b7d3374948d80fe47c22ded2d86ce46ddc3afada Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Jul 2016 10:56:52 +1000 Subject: [PATCH 39/61] these files were removed from master --- templates/typescript-angular-request.mustache | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 templates/typescript-angular-request.mustache diff --git a/templates/typescript-angular-request.mustache b/templates/typescript-angular-request.mustache deleted file mode 100644 index 7dffbc2b..00000000 --- a/templates/typescript-angular-request.mustache +++ /dev/null @@ -1,43 +0,0 @@ -var url = domain + path; -{{#isGET}} -var cached = opts.$cache && opts.$cache.get(url); -if(cached !== undefined && opts.$refresh !== true) { - deferred.resolve(cached); - return deferred.promise; -} -{{/isGET}} -var options = { - timeout: opts.$timeout, - method: '{{method}}', - url: url, - params: queryParameters, -{{#hasBody}} - data: body, -{{/hasBody}} -{{#hasForm}} - data: form, -{{/hasForm}} - headers: headers -}; -{{! I don't think this is actually needed #hasBody} } -if(typeof(body) === 'object' && !(body.constructor.name === 'Buffer')) { - options.headers['Content-Type'] = 'application/json'; -{ {/hasBody}} -{{#hasForm}} -options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; -options.transformRequest = {{&className}}.transformRequest; -{{/hasForm}} - -this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}>){ - {{#hasVoidReturn}} - deferred.resolve(); - {{/hasVoidReturn}} - {{^hasVoidReturn}} - deferred.resolve(response.data); - if(opts.$cache !== undefined) { - opts.$cache.put(url, response.data, opts.$cacheItemOpts ? opts.$cacheItemOpts : {}); - } - {{/hasVoidReturn}} -}, deferred.reject); - -return deferred.promise; From a7a6d33856f073d0cee607ec092f05adc08a19ad Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 27 Jul 2016 11:08:52 +1000 Subject: [PATCH 40/61] removed references to `template.request` --- lib/codegen.js | 2 +- tests/utilities.js | 105 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 tests/utilities.js diff --git a/lib/codegen.js b/lib/codegen.js index cc86915e..48f73fa7 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -290,7 +290,7 @@ var getCode = function(opts, type) { var data = opts.swagger.swagger === '2.0' ? getViewForSwagger2(opts, type) : getViewForSwagger1(opts, type); if (type === 'custom') { if (!_.isObject(opts.template) || !_.isString(opts.template.class) || !_.isString(opts.template.method)) { - throw new Error('Unprovided custom template. Please use the following template: template: { class: "...", method: "...", request: "..." }'); + throw new Error('Unprovided custom template. Please use the following template: template: { class: "...", method: "..." }'); } } else { selectTemplates(opts, type); diff --git a/tests/utilities.js b/tests/utilities.js new file mode 100644 index 00000000..188a08d5 --- /dev/null +++ b/tests/utilities.js @@ -0,0 +1,105 @@ +'use strict'; + +var assert = require('assert'); +var rewire = require('rewire'); +var vows = require('vows'); +var _ = require('lodash'); + +var CodeGen = rewire('../lib/codegen.js'); + +vows.describe('Test Utilities').addBatch({ + 'camelCase': { + topic: function(){ + return CodeGen.__get__('camelCase'); + }, + 'by default': { + topic: function(camelCase) { + return _.curry(camelCase)({}); + }, + 'should leave camelCase as camelCase': function(camelCase) { + assert.equal(camelCase('alreadyCamel'), 'alreadyCamel'); + }, + 'should convert kebab-case to camelCase': function(camelCase) { + assert.equal(camelCase('kebab-case'), 'kebabCase'); + assert.equal(camelCase('double-kebab-case'), 'doubleKebabCase'); + }, + 'should not convert snake_case to camelCase': function(camelCase) { + assert.equal(camelCase('snake_case'), 'snake_case'); + assert.equal(camelCase('double_snake_case'), 'double_snake_case'); + assert.equal(camelCase('snake_with-kebab'), 'snake_withKebab'); + } + }, + 'when convertSnakeCase is true': { + topic: function(camelCase) { + return _.curry(camelCase)({convertSnakeCase: true}); + }, + 'should leave camelCase as camelCase': function(camelCase) { + assert.equal(camelCase('alreadyCamel'), 'alreadyCamel'); + }, + 'should convert kebab-case to camelCase': function(camelCase) { + assert.equal(camelCase('kebab-case'), 'kebabCase'); + assert.equal(camelCase('double-kebab-case'), 'doubleKebabCase'); + }, + 'should convert snake_case to camelCase': function(camelCase) { + assert.equal(camelCase('snake_case'), 'snakeCase'); + assert.equal(camelCase('double_snake_case'), 'doubleSnakeCase'); + assert.equal(camelCase('snake_with-kebab'), 'snakeWithKebab'); + } + } + }, + 'selectTemplates': { + topic: function(){ + var locateTemplate = CodeGen.__get__('locateTemplate'); + CodeGen.__set__('readTemplate', function(path, language, framework, suffix) { + return locateTemplate(path, language, framework, suffix); + }); + return CodeGen.__get__('selectTemplates'); + }, + 'should be backward-compatible': { + topic: function(selectTemplates) { + return selectTemplates; //_.curry(selectTemplates)({}); + }, + 'with angular': function(selectTemplates) { + var opts = {}; + var dirname = __dirname.replace(/tests$/, 'lib') + '/../templates/'; + selectTemplates(opts, 'angular'); + assert.equal(opts.template.class, dirname + 'angular-class.mustache'); + assert.equal(opts.template.method, dirname + 'method.mustache'); + assert.equal(opts.template.type, undefined); + }, + 'with node': function(selectTemplates) { + var opts = {}; + var dirname = __dirname.replace(/tests$/, 'lib') + '/../templates/'; + selectTemplates(opts, 'node'); + assert.equal(opts.template.class, dirname + 'node-class.mustache'); + assert.equal(opts.template.method, dirname + 'method.mustache'); + assert.equal(opts.template.type, undefined); + }, + 'with typescript': function(selectTemplates) { + var opts = {}; + var dirname = __dirname.replace(/tests$/, 'lib') + '/../templates/'; + selectTemplates(opts, 'typescript'); + assert.equal(opts.template.class, dirname + 'typescript-class.mustache'); + assert.equal(opts.template.method, dirname + 'typescript-method.mustache'); + assert.equal(opts.template.type, dirname + 'type.mustache'); + } + } + }, + 'locateTemplate': { + topic: function(){ + return CodeGen.__get__('locateTemplate'); + }, + 'should find templates for language and framework': function(locateTemplate) { + assert.equal(locateTemplate(__dirname + '/../templates/', 'typescript', 'angular', 'class.mustache'), + __dirname + '/../templates/typescript-angular-class.mustache'); + }, + 'should find templates for language': function(locateTemplate) { + assert.equal(locateTemplate(__dirname + '/../templates/', 'typescript', undefined, 'class.mustache'), + __dirname + '/../templates/typescript-class.mustache'); + }, + 'should find templates for framework': function(locateTemplate) { + assert.equal(locateTemplate(__dirname + '/../templates/', undefined, 'angular', 'class.mustache'), + __dirname + '/../templates/angular-class.mustache'); + } + } +}).export(module); From c1851a36e7b5db65f808f4e7e98c2896982e0049 Mon Sep 17 00:00:00 2001 From: adrianwong Date: Mon, 1 Aug 2016 14:56:24 +1000 Subject: [PATCH 41/61] Moved code from "typescript-angular-request.mustache" into "typescript-angular-method.mustache" replacing "{{> request}}" tag. --- templates/typescript-angular-method.mustache | 46 +++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/templates/typescript-angular-method.mustache b/templates/typescript-angular-method.mustache index 6bcdb136..18512aca 100644 --- a/templates/typescript-angular-method.mustache +++ b/templates/typescript-angular-method.mustache @@ -99,5 +99,49 @@ if(parameters.$queryParameters) { queryParameters[parameterName] = parameter; }); } -{{> request}} + +var url = domain + path; +{{#isGET}} +var cached = opts.$cache && opts.$cache.get(url); +if(cached !== undefined && opts.$refresh !== true) { + deferred.resolve(cached); + return deferred.promise; +} +{{/isGET}} +var options = { + timeout: opts.$timeout, + method: '{{method}}', + url: url, + params: queryParameters, +{{#hasBody}} + data: body, +{{/hasBody}} +{{#hasForm}} + data: form, +{{/hasForm}} + headers: headers +}; +{{! I don't think this is actually needed #hasBody} } +if(typeof(body) === 'object' && !(body.constructor.name === 'Buffer')) { + options.headers['Content-Type'] = 'application/json'; +{ {/hasBody}} +{{#hasForm}} +options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; +options.transformRequest = {{&className}}.transformRequest; +{{/hasForm}} + +this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}>){ + {{#hasVoidReturn}} + deferred.resolve(); + {{/hasVoidReturn}} + {{^hasVoidReturn}} + deferred.resolve(response.data); + if(opts.$cache !== undefined) { + opts.$cache.put(url, response.data, opts.$cacheItemOpts ? opts.$cacheItemOpts : {}); + } + {{/hasVoidReturn}} +}, deferred.reject); + +return deferred.promise; + } From ba1097945cca87225f69ad75d4f721c81448f1d4 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Mon, 22 Aug 2016 14:53:39 +1000 Subject: [PATCH 42/61] restored tests for `selectTemplates`, `locateTemplate` --- tests/utilities.js | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/tests/utilities.js b/tests/utilities.js index 188a08d5..23b57c09 100644 --- a/tests/utilities.js +++ b/tests/utilities.js @@ -3,50 +3,10 @@ var assert = require('assert'); var rewire = require('rewire'); var vows = require('vows'); -var _ = require('lodash'); var CodeGen = rewire('../lib/codegen.js'); vows.describe('Test Utilities').addBatch({ - 'camelCase': { - topic: function(){ - return CodeGen.__get__('camelCase'); - }, - 'by default': { - topic: function(camelCase) { - return _.curry(camelCase)({}); - }, - 'should leave camelCase as camelCase': function(camelCase) { - assert.equal(camelCase('alreadyCamel'), 'alreadyCamel'); - }, - 'should convert kebab-case to camelCase': function(camelCase) { - assert.equal(camelCase('kebab-case'), 'kebabCase'); - assert.equal(camelCase('double-kebab-case'), 'doubleKebabCase'); - }, - 'should not convert snake_case to camelCase': function(camelCase) { - assert.equal(camelCase('snake_case'), 'snake_case'); - assert.equal(camelCase('double_snake_case'), 'double_snake_case'); - assert.equal(camelCase('snake_with-kebab'), 'snake_withKebab'); - } - }, - 'when convertSnakeCase is true': { - topic: function(camelCase) { - return _.curry(camelCase)({convertSnakeCase: true}); - }, - 'should leave camelCase as camelCase': function(camelCase) { - assert.equal(camelCase('alreadyCamel'), 'alreadyCamel'); - }, - 'should convert kebab-case to camelCase': function(camelCase) { - assert.equal(camelCase('kebab-case'), 'kebabCase'); - assert.equal(camelCase('double-kebab-case'), 'doubleKebabCase'); - }, - 'should convert snake_case to camelCase': function(camelCase) { - assert.equal(camelCase('snake_case'), 'snakeCase'); - assert.equal(camelCase('double_snake_case'), 'doubleSnakeCase'); - assert.equal(camelCase('snake_with-kebab'), 'snakeWithKebab'); - } - } - }, 'selectTemplates': { topic: function(){ var locateTemplate = CodeGen.__get__('locateTemplate'); From b999db0a48cf8aea106dc28c9dd8fc5778c0d1d4 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Mon, 22 Aug 2016 15:56:24 +1000 Subject: [PATCH 43/61] added support for optional fields --- lib/typescript.js | 5 ++--- templates/type.mustache | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/typescript.js b/lib/typescript.js index e07111dd..d1623043 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -14,7 +14,6 @@ var _ = require('lodash'); function convertType(swaggerType) { var typespec = {}; - if (swaggerType.hasOwnProperty('schema')) { return convertType(swaggerType.schema); } else if (_.isString(swaggerType.$ref)) { @@ -35,10 +34,10 @@ function convertType(swaggerType) { } else if (swaggerType.type === 'object') { typespec.tsType = 'object'; typespec.properties = []; - _.forEach(swaggerType.properties, function (propertyType, propertyName) { var property = convertType(propertyType); property.name = propertyName; + property.isOptional = !(swaggerType.required && _.includes(swaggerType.required, propertyName)); typespec.properties.push(property); }); } else { @@ -52,7 +51,7 @@ function convertType(swaggerType) { typespec.isObject = typespec.tsType === 'object'; typespec.isArray = typespec.tsType === 'array'; typespec.isAtomic = typespec.isAtomic || _.includes(['string', 'number', 'boolean', 'any'], typespec.tsType); - typespec.isAtomic = _.contains(['string', 'number', 'boolean', 'any'], typespec.tsType); + typespec.isOptional = !swaggerType.required; typespec.description = swaggerType.description; return typespec; diff --git a/templates/type.mustache b/templates/type.mustache index ada7c0cf..e81e2cbe 100644 --- a/templates/type.mustache +++ b/templates/type.mustache @@ -1,11 +1,12 @@ {{#tsType}} {{! must use different delimiters to avoid ambiguities when delimiters directly follow a literal brace {. }} - {{=<% %>=}} - <%#isRef%><%target%><%/isRef%><%! - %><%#isAtomic%><%&tsType%><%/isAtomic%><%! - %><%#isObject%>{<%#properties%> - '<%name%>': <%>type%><%/properties%> - }<%/isObject%><%! - %><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>>|<%#elementType%><%>type%><%/elementType%><%/isArray%> - <%={{ }}=%> -{{/tsType}} \ No newline at end of file +{{=<% %>=}} +<%#isRef%><%target%><%/isRef%><%! +%><%#isAtomic%><%tsType%><%/isAtomic%><%! +%><%#isObject%>{<%#properties%> +<%#description%>/** <%description%> */<%/description%> +<%name%><%#isOptional%>?<%/isOptional%>: <%>type%>;<%/properties%> +}<%/isObject%><%! +%><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>>|<%#elementType%><%>type%><%/elementType%><%/isArray%><%#isBoolean%>boolean<%/isBoolean%><%! +%><%={{ }}=%>{{/tsType}} +>>>>>>> added support for optional fields From 329ee2ca5be69d42b2aea2efe9e7ac9168486ab9 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Mon, 22 Aug 2016 16:42:00 +1000 Subject: [PATCH 44/61] default response is not always 200/201 - fallback to "any " --- lib/typescript.js | 1 - templates/typescript-angular-method.mustache | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/typescript.js b/lib/typescript.js index d1623043..1db6d98d 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -55,7 +55,6 @@ function convertType(swaggerType) { typespec.description = swaggerType.description; return typespec; - } module.exports.convertType = convertType; diff --git a/templates/typescript-angular-method.mustache b/templates/typescript-angular-method.mustache index 18512aca..451173d8 100644 --- a/templates/typescript-angular-method.mustache +++ b/templates/typescript-angular-method.mustache @@ -22,7 +22,7 @@ put:(key: string, value: string|Object, options?: {}) => void; }; $cacheItemOpts?: {}; - } = {}): ng.IPromise<{{&tsType}}> { + } = {}): ng.IPromise<{{&tsType}}|any> { let domain = this.domain; let path = '{{&path}}'; {{#hasBody}} @@ -130,7 +130,7 @@ options.headers['Content-Type'] = 'application/x-www-form-urlencoded'; options.transformRequest = {{&className}}.transformRequest; {{/hasForm}} -this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}>){ +this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}|any>){ {{#hasVoidReturn}} deferred.resolve(); {{/hasVoidReturn}} From 2e33e39f62f803abd84dcde3e723144adb58c187 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Thu, 1 Dec 2016 15:28:12 +1100 Subject: [PATCH 45/61] reject responses with status codes >= 400 --- templates/typescript-angular-method.mustache | 22 ++++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/templates/typescript-angular-method.mustache b/templates/typescript-angular-method.mustache index 451173d8..de9663da 100644 --- a/templates/typescript-angular-method.mustache +++ b/templates/typescript-angular-method.mustache @@ -10,7 +10,7 @@ {{/parameters}} */ {{&methodName}}(parameters: { -{{#parameters}}{{^isSingleton}}'{{&camelCaseName}}'{{&cardinality}}: {{> type}}, +{{#parameters}}{{^isSingleton}}{{&camelCaseName}}{{&cardinality}}: {{> type}}, {{/isSingleton}}{{/parameters}} $queryParameters?: {}, }, @@ -131,15 +131,19 @@ options.transformRequest = {{&className}}.transformRequest; {{/hasForm}} this.$http(options).then(function(response: ng.IHttpPromiseCallbackArg<{{&tsType}}|any>){ - {{#hasVoidReturn}} - deferred.resolve(); - {{/hasVoidReturn}} - {{^hasVoidReturn}} - deferred.resolve(response.data); - if(opts.$cache !== undefined) { - opts.$cache.put(url, response.data, opts.$cacheItemOpts ? opts.$cacheItemOpts : {}); + if(response.status >= 400) { + deferred.reject(response); + } else { + {{#hasVoidReturn}} + deferred.resolve(); + {{/hasVoidReturn}} + {{^hasVoidReturn}} + deferred.resolve(response.data); + if(opts.$cache !== undefined) { + opts.$cache.put(url, response.data, opts.$cacheItemOpts ? opts.$cacheItemOpts : {}); + } + {{/hasVoidReturn}} } - {{/hasVoidReturn}} }, deferred.reject); return deferred.promise; From 61c5d08dac1800437a208771778aac85daef8a7a Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Thu, 1 Dec 2016 15:31:05 +1100 Subject: [PATCH 46/61] don't generate code for OPTIONS requests --- lib/codegen.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codegen.js b/lib/codegen.js index 48f73fa7..22cf9c3c 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -184,6 +184,8 @@ var getViewForSwagger1 = function(opts, type){ }; swagger.apis.forEach(function(api){ api.operations.forEach(function(op){ + if (op.method == 'OPTIONS') return; + var method = { path: api.path, className: opts.className, From a3d9d5c8dff648da9b07fc14fe23a1bd415b308f Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Thu, 1 Dec 2016 16:00:50 +1100 Subject: [PATCH 47/61] don't generate code for OPTIONS requests --- lib/codegen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codegen.js b/lib/codegen.js index 22cf9c3c..148cfca9 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -57,7 +57,7 @@ var getViewForSwagger2 = function(opts, type){ } }); _.forEach(api, function(op, m){ - if(authorizedMethods.indexOf(m.toUpperCase()) === -1) { + if(authorizedMethods.indexOf(m.toUpperCase()) === -1 || m.toUpperCase() == 'OPTIONS') { return; } var method = { From b18e754cd1d7fb4c888ac46516f4473be91f328d Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Fri, 3 Feb 2017 15:45:08 +1100 Subject: [PATCH 48/61] Array is not implicity Array|Element --- templates/type.mustache | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/templates/type.mustache b/templates/type.mustache index e81e2cbe..984eee4e 100644 --- a/templates/type.mustache +++ b/templates/type.mustache @@ -6,7 +6,5 @@ %><%#isObject%>{<%#properties%> <%#description%>/** <%description%> */<%/description%> <%name%><%#isOptional%>?<%/isOptional%>: <%>type%>;<%/properties%> -}<%/isObject%><%! -%><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>>|<%#elementType%><%>type%><%/elementType%><%/isArray%><%#isBoolean%>boolean<%/isBoolean%><%! +}<%/isObject%><%!%><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>><%/isArray%><%#isBoolean%>boolean<%/isBoolean%><%! %><%={{ }}=%>{{/tsType}} ->>>>>>> added support for optional fields From 387f80b85535b6396193a430332fb438a955e447 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Fri, 3 Feb 2017 15:46:34 +1100 Subject: [PATCH 49/61] treat `type:array` definitions as `type name = ...` --- templates/typescript-angular-class.mustache | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/templates/typescript-angular-class.mustache b/templates/typescript-angular-class.mustache index 8994bd4b..7652b94b 100644 --- a/templates/typescript-angular-class.mustache +++ b/templates/typescript-angular-class.mustache @@ -4,11 +4,12 @@ module {{moduleName}} { -{{#types}} +{{#definitions}} {{#description}}/** {{description}} */{{/description}} - export interface {{name}} {{> type}} + {{#isObject}}export interface {{name}} {{> type}}{{/isObject}} + {{#isArray}}export type {{name}} = {{> type}};{{/isArray}} -{{/types}} +{{/definitions}} /** * {{&description}} From dc2b3e666f8c408eaaada6c4b22591a83a3c4c0e Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Fri, 3 Feb 2017 16:10:45 +1100 Subject: [PATCH 50/61] updated as per master --- templates/typescript-angular-class.mustache | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/templates/typescript-angular-class.mustache b/templates/typescript-angular-class.mustache index 7652b94b..e79be17e 100644 --- a/templates/typescript-angular-class.mustache +++ b/templates/typescript-angular-class.mustache @@ -6,8 +6,7 @@ module {{moduleName}} { {{#definitions}} {{#description}}/** {{description}} */{{/description}} - {{#isObject}}export interface {{name}} {{> type}}{{/isObject}} - {{#isArray}}export type {{name}} = {{> type}};{{/isArray}} + export type {{&name}} = {{#tsType}}{{> type}}{{/tsType}}; {{/definitions}} From 6f69a3636ed40aea6cc9f8b6065b276ae2195ee3 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 22 Mar 2017 11:42:16 +1100 Subject: [PATCH 51/61] switched from `/// reference` to `import` --- templates/typescript-angular-class.mustache | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/templates/typescript-angular-class.mustache b/templates/typescript-angular-class.mustache index 202f451c..7fe6bb1d 100644 --- a/templates/typescript-angular-class.mustache +++ b/templates/typescript-angular-class.mustache @@ -1,8 +1,6 @@ -{{#imports}} -/// -{{/imports}} +import * as angular from 'angular'; -module {{moduleName}} { +export module {{moduleName}} { {{#definitions}} {{#description}}/** {{description}} */{{/description}} From 4292e4240549e179942716ebfc33c35766388021 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 22 Mar 2017 11:42:46 +1100 Subject: [PATCH 52/61] v1.7.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8f4c0852..29ad21d8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "swagger-js-codegen", "main": "./lib/codegen.js", - "version": "1.7.12", + "version": "1.7.13", "description": "A Swagger codegen for JavaScript", "scripts": { "test": "grunt", From 429ff00dde5a0ef4820a2420b0850b8c66a06c1e Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Tue, 28 Mar 2017 17:28:05 +1100 Subject: [PATCH 53/61] single quotes --- lib/typescript.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/typescript.js b/lib/typescript.js index 1db6d98d..92de529b 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -20,7 +20,9 @@ function convertType(swaggerType) { typespec.tsType = 'ref'; typespec.target = swaggerType.$ref.substring(swaggerType.$ref.lastIndexOf('/') + 1); } else if (swaggerType.hasOwnProperty('enum')) { - typespec.tsType = swaggerType.enum.map(function(str) { return JSON.stringify(str); }).join(' | '); + typespec.tsType = swaggerType.enum.map(function(str) { + return typeof str == 'string' ? '\'' + str + '\'' : JSON.stringify(str); + }).join(' | '); typespec.isAtomic = true; } else if (swaggerType.type === 'string') { typespec.tsType = 'string'; From eb63436b1676df7c0aa36b40ae39c932611ebe22 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Tue, 28 Mar 2017 17:28:14 +1100 Subject: [PATCH 54/61] v1.7.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29ad21d8..aec6465c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "swagger-js-codegen", "main": "./lib/codegen.js", - "version": "1.7.13", + "version": "1.7.14", "description": "A Swagger codegen for JavaScript", "scripts": { "test": "grunt", From 5c20749da22a69163a06ee79cb254e60971890c3 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Tue, 28 Mar 2017 17:51:47 +1100 Subject: [PATCH 55/61] v1.7.15 --- package.json | 2 +- templates/typescript-angular-class.mustache | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index aec6465c..1c474077 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "swagger-js-codegen", "main": "./lib/codegen.js", - "version": "1.7.14", + "version": "1.7.15", "description": "A Swagger codegen for JavaScript", "scripts": { "test": "grunt", diff --git a/templates/typescript-angular-class.mustache b/templates/typescript-angular-class.mustache index 7fe6bb1d..23891bde 100644 --- a/templates/typescript-angular-class.mustache +++ b/templates/typescript-angular-class.mustache @@ -1,3 +1,4 @@ +/* tslint:disable */ import * as angular from 'angular'; export module {{moduleName}} { From ad66a98acbc9399d01b25cd4e049771aabe64768 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 10 May 2017 15:16:50 +1000 Subject: [PATCH 56/61] fixed handling of arrays in query, optionally with enum --- lib/typescript.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/typescript.js b/lib/typescript.js index 92de529b..62e66b54 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -19,6 +19,21 @@ function convertType(swaggerType) { } else if (_.isString(swaggerType.$ref)) { typespec.tsType = 'ref'; typespec.target = swaggerType.$ref.substring(swaggerType.$ref.lastIndexOf('/') + 1); + } else if (swaggerType.type === 'array') { + if (swaggerType.in === 'query' && swaggerType.collectionFormat !== 'multi') { + // arrays in query parameters are merged by csv, ssv, tsv or pipes + typespec.tsType = 'string'; + if (swaggerType.hasOwnProperty('enum')) { + // doesn't affect the compiler, but useful for documentation + typespec.tsType += ' | ' + swaggerType.enum.map(function (str) { + return typeof str == 'string' ? '\'' + str + '\'' : JSON.stringify(str); + }).join(' | '); + typespec.isAtomic = true; + } + } else { + typespec.tsType = 'array'; + } + typespec.elementType = convertType(swaggerType.items); } else if (swaggerType.hasOwnProperty('enum')) { typespec.tsType = swaggerType.enum.map(function(str) { return typeof str == 'string' ? '\'' + str + '\'' : JSON.stringify(str); @@ -30,9 +45,6 @@ function convertType(swaggerType) { typespec.tsType = 'number'; } else if (swaggerType.type === 'boolean') { typespec.tsType = 'boolean'; - } else if (swaggerType.type === 'array') { - typespec.tsType = 'array'; - typespec.elementType = convertType(swaggerType.items); } else if (swaggerType.type === 'object') { typespec.tsType = 'object'; typespec.properties = []; @@ -44,7 +56,7 @@ function convertType(swaggerType) { }); } else { // type unknown or unsupported... just map to 'any'... - // TODO: probably void + // TODO: probably void or allOf:[] typespec.tsType = 'any'; } From 7fbaa1649c3901a25bd8b165d3f822577b1df28c Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Thu, 11 May 2017 14:02:25 +1000 Subject: [PATCH 57/61] v1.7.15-a --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1c474077..2c189699 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "swagger-js-codegen", "main": "./lib/codegen.js", - "version": "1.7.15", + "version": "1.7.15-a", "description": "A Swagger codegen for JavaScript", "scripts": { "test": "grunt", From 534fd1c0a2cd692cc1f42a4613d2f8025a8be5a5 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 17 May 2017 18:01:27 +1000 Subject: [PATCH 58/61] support `basePath` --- lib/codegen.js | 1 + templates/typescript-angular-method.mustache | 2 +- templates/typescript-method.mustache | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/codegen.js b/lib/codegen.js index 5ae9f76c..9acb4448 100644 --- a/lib/codegen.js +++ b/lib/codegen.js @@ -41,6 +41,7 @@ var getViewForSwagger2 = function(opts, type){ className: opts.className, imports: opts.imports, domain: (swagger.schemes && swagger.schemes.length > 0 && swagger.host && swagger.basePath) ? swagger.schemes[0] + '://' + swagger.host + swagger.basePath.replace(/\/+$/g,'') : '', + basePath: swagger.basePath, methods: [], definitions: [] }; diff --git a/templates/typescript-angular-method.mustache b/templates/typescript-angular-method.mustache index de9663da..6fd01f68 100644 --- a/templates/typescript-angular-method.mustache +++ b/templates/typescript-angular-method.mustache @@ -24,7 +24,7 @@ $cacheItemOpts?: {}; } = {}): ng.IPromise<{{&tsType}}|any> { let domain = this.domain; - let path = '{{&path}}'; + let path = '{{&basePath}}{{&path}}'; {{#hasBody}} let body; {{/hasBody}} diff --git a/templates/typescript-method.mustache b/templates/typescript-method.mustache index a340ac64..47ceb2b7 100644 --- a/templates/typescript-method.mustache +++ b/templates/typescript-method.mustache @@ -6,7 +6,7 @@ $domain?: string }): string { let queryParameters: any = {}; const domain = parameters.$domain ? parameters.$domain : this.domain; - let path = '{{&path}}'; + let path = '{{&basePath}}{{&path}}'; {{#parameters}} {{#isQueryParameter}} {{#isSingleton}} From ed6d3fa5e8ce2c4bcf82a392592f257cff7fe6c2 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Wed, 17 May 2017 18:04:02 +1000 Subject: [PATCH 59/61] v1.7.15-b --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2c189699..5c1c0833 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "swagger-js-codegen", "main": "./lib/codegen.js", - "version": "1.7.15-a", + "version": "1.7.15-b", "description": "A Swagger codegen for JavaScript", "scripts": { "test": "grunt", From 7c92ac0efb05a456fbaf0695bd6bf56fe7e52ab6 Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Thu, 18 May 2017 13:18:14 +1000 Subject: [PATCH 60/61] support allOf --- lib/typescript.js | 13 +++++++++++-- templates/type.mustache | 8 +++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/typescript.js b/lib/typescript.js index 62e66b54..ae7a6897 100644 --- a/lib/typescript.js +++ b/lib/typescript.js @@ -14,7 +14,16 @@ var _ = require('lodash'); function convertType(swaggerType) { var typespec = {}; - if (swaggerType.hasOwnProperty('schema')) { + if (swaggerType.hasOwnProperty('allOf')) { + typespec.isIntersection = true; + typespec.items = swaggerType.allOf.map(function(item) { + // join with '&' and avoid 'RangeError: Maximum call stack size exceeded' + return Object.assign(convertType(item), {hasPrefix: true, isIntersection: false}); + }); + typespec.items[0].hasPrefix = false; + typespec.tsType = 'intersection'; + + } else if (swaggerType.hasOwnProperty('schema')) { return convertType(swaggerType.schema); } else if (_.isString(swaggerType.$ref)) { typespec.tsType = 'ref'; @@ -56,7 +65,7 @@ function convertType(swaggerType) { }); } else { // type unknown or unsupported... just map to 'any'... - // TODO: probably void or allOf:[] + // TODO: probably void typespec.tsType = 'any'; } diff --git a/templates/type.mustache b/templates/type.mustache index 04308088..bd9b87fa 100644 --- a/templates/type.mustache +++ b/templates/type.mustache @@ -1,10 +1,12 @@ {{#tsType}} {{! must use different delimiters to avoid ambiguities when delimiters directly follow a literal brace {. }} {{=<% %>=}} -<%#isRef%><%target%><%/isRef%><%! +<%#isIntersection%><%#items%><%#hasPrefix%>&<%/hasPrefix%><%>type%><%/items%><%/isIntersection%><%! +%><%#isRef%><%target%><%/isRef%><%! %><%#isAtomic%><%&tsType%><%/isAtomic%><%! %><%#isObject%>{<%#properties%><%#description%>/** <%description%> */<%/description%> <%name%><%#isOptional%>?<%/isOptional%>: <%>type%>;<%/properties%> }<%/isObject%><%! -%><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>>|<%#elementType%><%>type%><%/elementType%><%/isArray%><%#isBoolean%>boolean<%/isBoolean%><%! -%><%={{ }}=%>{{/tsType}} \ No newline at end of file +%><%#isArray%>Array<<%#elementType%><%>type%><%/elementType%>><%/isArray%><%! +%><%#isBoolean%>boolean<%/isBoolean%><%! +%><%={{ }}=%>{{/tsType}} From cd00549230e2ce4a083fe8fc473668f8dab008ee Mon Sep 17 00:00:00 2001 From: Nicholas Albion Date: Thu, 18 May 2017 13:18:34 +1000 Subject: [PATCH 61/61] v1.7.15-c --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5c1c0833..5e16dcdf 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "swagger-js-codegen", "main": "./lib/codegen.js", - "version": "1.7.15-b", + "version": "1.7.15-c", "description": "A Swagger codegen for JavaScript", "scripts": { "test": "grunt",