UNPKG

webapi-ng2

Version:

ASP.NET Core Web API client generator for Angular 2

321 lines 24.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var specification_1 = require("../../specification"); var AngularGenerator = /** @class */ (function () { function AngularGenerator() { } AngularGenerator.prototype.generate = function (specification, config) { // if (apiDescription.definitions != undefined) { // this.mapDefinitions(apiDescription.definitions); // } var script = this.getHeader() + '\n\r' + this.getImports() + '\n\r' + this.getOptions(config) + '\n\r' + this.getBaseClass(config) + '\n\r'; for (var _i = 0, _a = specification.controllers; _i < _a.length; _i++) { var controller = _a[_i]; script += '\n\r' + this.getController(controller, config); } if (specification.schema != undefined) { var enumTypes = []; for (var schemaName in specification.schema) { var schema = specification.schema[schemaName]; script += '\n\r' + this.getSchema(schema); if (schema.type == specification_1.SchemaType.Enumeration) { enumTypes.push(schema); } } if (enumTypes.length > 0) { script += '\n\r' + this.getEnumService(enumTypes); } } return script; }; AngularGenerator.prototype.getHeader = function () { var result = "\n //\n // This file is autogenerated.\n // See http://github.com/bmitchenko/webapi-ng2 for details.\n //\n // tslint:disable:max-line-length\n "; return result; }; AngularGenerator.prototype.getImports = function () { var result = "\n import { Injectable } from '@angular/core';\n import { HttpClient, HttpParams, HttpEvent, HttpResponse, HttpErrorResponse, HttpRequest, HttpHeaders } from '@angular/common/http';\n "; return result; }; AngularGenerator.prototype.getOptions = function (config) { var result = "\n @Injectable()\n export class " + config.outputClass + "Options {\n public basePath = '';\n public loginUrl: string;\n public dateSerialization: 'local' | 'utc' = 'utc';\n }"; return result; }; AngularGenerator.prototype.getEnumService = function (enumTypes) { var enumMetadata = []; for (var _i = 0, enumTypes_1 = enumTypes; _i < enumTypes_1.length; _i++) { var enumType = enumTypes_1[_i]; var displayName = void 0; if (enumType.attributes != undefined) { displayName = this.getDisplayName(enumType.attributes); } if (displayName == undefined) { displayName = enumType.name; } var values = []; if (enumType.values != undefined) { for (var _a = 0, _b = enumType.values; _a < _b.length; _a++) { var enumValue = _b[_a]; var valueDisplayName = void 0; if (enumValue.attributes != undefined) { valueDisplayName = this.getDisplayName(enumValue.attributes); } if (valueDisplayName == undefined) { valueDisplayName = enumValue.name; } values.push("{ value: " + enumType.name + "." + enumValue.name + ", displayName: '" + valueDisplayName + "' }"); } } enumMetadata.push("\n {\n type: " + enumType.name + ",\n displayName: '" + displayName + "',\n values: [\n " + values.join(',\r') + "\n ]\n }"); } var result = "\n export interface EnumValue<T> {\n displayName: string;\n value: T;\n }\n \n interface EnumMetadata<T> {\n displayName: string;\n type: any;\n values: EnumValue<T>[];\n }\n\n export const ENUM_METADATA: EnumMetadata<any>[] = [\n " + enumMetadata.join(',') + "\n ];\n\n @Injectable()\n export class EnumService {\n public getDisplayName(enumType: any): string {\n const metadata = this.findEnum<any>(enumType);\n \n return metadata.displayName;\n }\n \n public getValueDisplayName(enumType: any, enumValue: number): string {\n const metadata = this.findEnum<any>(enumType);\n\n const exactValue = metadata.values.find(x => x.value === enumValue);\n \n if (exactValue != undefined) {\n return exactValue.displayName;\n }\n \n const result = metadata.values\n // tslint:disable-next-line:no-bitwise\n .filter(x => x.value !== 0 && (x.value & enumValue) === x.value)\n .map(x => x.displayName);\n \n return result.join(', ');\n }\n \n public getValues<T>(enumType: any): EnumValue<T>[] {\n const metadata = this.findEnum<any>(enumType);\n \n return metadata.values;\n }\n \n private findEnum<T>(enumType: any): EnumMetadata<T> {\n const metadata = ENUM_METADATA.find(x => x.type === enumType);\n \n if (metadata == undefined) {\n throw Error('Metadata for enum type not found.');\n }\n \n return metadata;\n } \n }"; return result; }; AngularGenerator.prototype.getDisplayName = function (attributes) { var displayAttribute = attributes.find(function (x) { return x.name == 'DisplayName'; }); if (displayAttribute != undefined) { if (displayAttribute.parameters != undefined) { var nameParameter = displayAttribute.parameters.find(function (x) { return x.name == 'displayName'; }); if (nameParameter != undefined) { return nameParameter.value; } } } return undefined; }; AngularGenerator.prototype.getBaseClass = function (config) { var returnType = config.usePromises ? 'Promise<T>' : 'Observable<T>'; var toPromise = config.usePromises ? '.toPromise()' : ''; var result = "\n @Injectable()\n export abstract class " + config.outputClass + "Base {\n private dateFormat = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}.*/;\n\n constructor(public http: HttpClient, public options: " + config.outputClass + "Options) {\n this.reviver = this.reviver.bind(this);\n }\n\n protected request<T>(path: string, method: string, urlParams?: any, body?: any): Promise<T> {\n let url = path;\n let params = new HttpParams();\n \n if (urlParams !== undefined) {\n Object.getOwnPropertyNames(urlParams).forEach((paramName) => {\n if (url.indexOf(" + "`{${paramName}}`" + ") !== -1) {\n url = url.replace(" + "`{${paramName}}`" + ", urlParams[paramName]);\n } else {\n params = this.addSearchParam(params, paramName, urlParams[paramName]);\n }\n });\n }\n\n body = this.serializeBody(body);\n \n const request = new HttpRequest<any>(method, this.options.basePath + url, body, {\n headers: new HttpHeaders({ 'Content-Type': 'application/json' }),\n params: params,\n responseType: 'text'\n });\n \n const promise = new Promise<any>((resolve, reject) => {\n this.http.request(request).subscribe((event: HttpEvent<any>) => {\n if (event instanceof HttpResponse) {\n resolve(this.extractBody(event));\n }\n }, (error: HttpErrorResponse | Error) => {\n if (error instanceof Error) {\n reject(error);\n } else {\n reject(this.extractError(error));\n }\n });\n });\n \n return promise;\n }\n\n private extractBody(response: HttpResponse<any>): any {\n let body = response.body;\n \n if (typeof body === 'string') {\n if (this.isJsonResponse(response)) {\n try {\n body = this.parseJson(body);\n } catch (e) {\n }\n }\n }\n \n return body;\n }\n \n private extractError(response: HttpErrorResponse): Error {\n if (response.error instanceof Error) {\n return response.error;\n } else {\n if (this.isJsonResponse(response)) {\n let body = response.error;\n \n if (typeof body === 'string') {\n body = this.parseJson(body);\n }\n \n const error = new Error(body.message);\n \n if ('validationErrors' in body) {\n error['validationErrors'] = body.validationErrors;\n }\n \n return error;\n } else {\n return new Error(response.error);\n }\n }\n }\n\n private serializeBody(body?: any) {\n if (body == undefined) {\n return body;\n }\n \n if (typeof body !== 'object') {\n return body;\n }\n \n return JSON.stringify(body, (key, value) => {\n if (typeof value === 'string' && this.dateFormat.test(value)) {\n return this.serializeDate(new Date(value));\n }\n \n return value;\n });\n }\n \n private serializeDate(d: Date): string {\n let result: string;\n \n const n = x => x < 10 ? '0' + x.toString() : x.toString();\n \n if (this.options.dateSerialization === 'local') {\n result =\n n(d.getMonth() + 1) + '/' +\n n(d.getDate()) + '/' +\n d.getFullYear() + ' ' +\n n(d.getHours()) + ':' +\n n(d.getMinutes()) + ':' +\n n(d.getSeconds());\n } else {\n result = d.toJSON();\n }\n \n return result;\n } \n\n private isJsonResponse(response: HttpResponse<any> | HttpErrorResponse): boolean {\n const contentType = response.headers.get('content-type');\n \n if (contentType && contentType.indexOf('application/json') !== -1) {\n return true;\n }\n \n return false;\n }\n \n private parseJson(text: string): any {\n return JSON.parse(text, this.reviver);\n }\n \n private reviver(key: any, value: any) {\n if (typeof value === 'string' && this.dateFormat.test(value)) {\n return new Date(value);\n }\n \n return value;\n }\n \n private addSearchParam(params: HttpParams, name: string, value: any): HttpParams {\n if (value instanceof Array) {\n value.forEach((v, i) => {\n params = this.addSearchParam(params, " + "`${name}[${i}]`" + ", v);\n });\n } else {\n if (value instanceof Date) {\n params = params.append(name, value.toUTCString());\n } else {\n if (value instanceof Object) {\n Object.getOwnPropertyNames(value).forEach((propertyName) => {\n params = this.addSearchParam(params, " + "`${name}.${propertyName}`" + ", value[propertyName]);\n });\n } else {\n if (value) {\n params = params.append(name, value);\n }\n }\n }\n }\n \n return params;\n }\n }"; return result; }; AngularGenerator.prototype.getController = function (controller, config) { var operations = []; if (controller.operations != undefined) { for (var _i = 0, _a = controller.operations; _i < _a.length; _i++) { var operation = _a[_i]; operations.push(this.getOperation(operation, config)); } } var className = controller.name; if (!className.endsWith('Service')) { className += 'Service'; } var result = "\n @Injectable()\n export class " + className + " extends " + config.outputClass + ("Base {\n " + operations.join('') + "\n }"); return result; }; AngularGenerator.prototype.getOperation = function (operation, config) { var path = operation.path; var method = operation.method; var urlParams = ''; var bodyParam = undefined; var name = this.camelCase(operation.name); var returnTypeArgument = this.mapType(operation.responseType); var returnType = config.usePromises ? "Promise<" + returnTypeArgument + ">" : "Observable<" + returnTypeArgument + ">"; var parameters = []; if (operation.parameters != undefined) { for (var _i = 0, _a = operation.parameters; _i < _a.length; _i++) { var parameter = _a[_i]; var source = parameter.in.toLowerCase(); if (source == 'body') { bodyParam = parameter.name; } if (source == 'query' || source == 'path') { if (urlParams.length > 0) { urlParams += ', '; } urlParams += parameter.name + ": " + parameter.name; } parameters.push(this.getOperationParameter(parameter)); } } var requestParameters = "'" + path + "', '" + method + "'"; if (urlParams.length > 0 || bodyParam != undefined) { requestParameters += ", { " + urlParams + " }"; } if (bodyParam != undefined) { requestParameters += ", " + bodyParam; } var operationMethod = "\n public " + name + "(" + parameters.join() + "): " + returnType + " {\n return this.request<" + returnTypeArgument + ">(" + requestParameters + ");\n }\n "; if (operation.summary) { operationMethod = "/** " + operation.summary + " */ " + operationMethod; } return operationMethod; }; AngularGenerator.prototype.getOperationParameter = function (operationParameter) { var parameter = operationParameter.name; if (!operationParameter.required && operationParameter.default == undefined) { parameter += '?'; } var parameterType = this.mapType(operationParameter.type); parameter += ": " + parameterType; if (!operationParameter.required) { var defaultValue = operationParameter.default; if (defaultValue != undefined) { if (parameterType == 'string') { defaultValue = "'" + defaultValue + "'"; } parameter += " = " + defaultValue; } } return parameter; }; AngularGenerator.prototype.getSchema = function (schema) { if (schema.type === specification_1.SchemaType.Enumeration) { return this.getEnum(schema); } return this.getInterface(schema); }; AngularGenerator.prototype.getEnum = function (schema) { var values = []; if (schema.values != undefined) { for (var _i = 0, _a = schema.values; _i < _a.length; _i++) { var enumValue = _a[_i]; if (enumValue.value != undefined) { values.push(enumValue.name + " = " + enumValue.value); } else { values.push(enumValue.name); } } } var result = "\n export enum " + schema.name + " {\n " + values.join(', \n') + "\n }"; return result; }; AngularGenerator.prototype.getInterface = function (schema) { var _this = this; var base = ''; var properties = []; if (schema.extends != undefined) { base = "extends " + schema.extends.map(function (x) { return _this.mapType(x); }).join(', '); } if (schema.properties != undefined) { for (var _i = 0, _a = schema.properties; _i < _a.length; _i++) { var property = _a[_i]; var propertyName = this.camelCase(property.name); var propertyType = this.mapType(property.type); if (property.nullable) { propertyName += '?'; } properties.push(propertyName + ": " + propertyType + ";"); } } var result = "\n export interface " + schema.name + " " + base + " {\n " + properties.join('\n') + "\n }"; return result; }; AngularGenerator.prototype.mapType = function (coreType) { // collection; var _this = this; if (coreType.endsWith('[]')) { var collectionType = this.mapType(coreType.substr(0, coreType.length - 2)); return collectionType + "[]"; } // generic type; if (coreType.endsWith('>')) { var genericType = this.parseGenericType(coreType); var genericArguments = genericType.arguments .map(function (x) { return _this.mapType(x); }) .join(', '); return genericType.name + "<" + genericArguments + ">"; } // primitive; switch (coreType.toLowerCase()) { case 'guid': case 'string': return 'string'; case 'datetime': return 'Date'; case 'bool': case 'boolean': return 'boolean'; case 'byte': case 'short': case 'int': case 'integer': case 'int16': case 'int32': case 'int64': case 'float': case 'decimal': case 'double': case 'single': return 'number'; case 'void': return 'void'; case 'object': return 'any'; default: break; } // interface; return coreType; }; AngularGenerator.prototype.parseGenericType = function (typeName) { var open = typeName.indexOf('<'); var genericName = typeName.substr(0, open); var genericArguments = []; var splitters; var level = 0; var buf = ''; for (var i = open + 1; i < typeName.length - 1; i++) { var c = typeName[i]; if (c == '<') { level++; } else if (c == '>') { level--; } else if (c == ',' && level == 0) { genericArguments.push(buf.trim()); buf = ''; } if (c != ',' || level > 0) { buf += c; } } genericArguments.push(buf.trim()); return { arguments: genericArguments, name: genericName }; }; AngularGenerator.prototype.camelCase = function (text) { return text.substr(0, 1).toLowerCase() + text.substr(1); }; return AngularGenerator; }()); exports.AngularGenerator = AngularGenerator; // private getApi(apiDescription: ApiDescription, config: GeneratorConfig): string { // let fields: string[] = []; // let properties: string[] = []; // if (apiDescription.controllers != undefined) { // apiDescription.controllers.forEach((controller) => { // var className = controller.name + 'Controller'; // var fieldName = '_' + this.camelCase(controller.name); // fields.push(`private ${fieldName}: ${className};`); // var property = `public get ${this.camelCase(controller.name)}(): ${className} { // if (this.${fieldName} == undefined) { // this.${fieldName} = new ${className}(this._connection); // } // return this.${fieldName}; // }`; // properties.push(property); // }); // } // return ` // @Injectable() // export class ${config.outputClass} { // private _connection: ApiConnection; // ${fields.join('\n')} // constructor (http: Http) { // this._connection = new ApiConnection(http, ''); // } // public get basePath(): string { // return this._connection.basePath; // } // public set basePath(basePath: string) { // this._connection.basePath = basePath; // } // ${properties.join('\n')} // }`; // } //# sourceMappingURL=angular-generator.js.map