UNPKG

webapi-ng2

Version:

ASP.NET Core Web API client generator for Angular 2

343 lines 27 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AngularGenerator = void 0; 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 import { map, filter, catchError } from 'rxjs/operators';\n import { Observable, throwError } from 'rxjs';\n "; return result; }; AngularGenerator.prototype.getOptions = function (config) { var result = "\n export class HttpError extends Error {\n detail?: string;\n error?: any;\n status: number;\n title?: string;\n traceId?: string;\n type?: string;\n url: string;\n \n constructor(message?: string) {\n super(message);\n }\n }\n\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; } } } var descriptionAttribute = attributes.find(function (x) { return x.name == 'Description'; }); if (descriptionAttribute != undefined) { if (descriptionAttribute.parameters != undefined) { var nameParameter = descriptionAttribute.parameters.find(function (x) { return x.name == 'description'; }); if (nameParameter != undefined) { return nameParameter.value; } } } var displayNameAttribute = attributes.find(function (x) { return x.name == 'Display'; }); if (displayNameAttribute != undefined) { if (displayNameAttribute.parameters != undefined) { var nameParameter = displayNameAttribute.parameters.find(function (x) { return x.name == 'Name'; }); if (nameParameter != undefined) { return nameParameter.value; } } } return undefined; }; AngularGenerator.prototype.getBaseClass = function (config) { 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 " + this.getRequestMethod(config) + "\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 const error = new HttpError(response.message);\n \n error.status = response.status;\n error.url = response.url;\n \n const contentType = response.headers.get('content-type');\n \n if (contentType?.includes('application/problem+json')) {\n const problemDetail = JSON.parse(response.error);\n \n if (problemDetail.detail != null) {\n error.detail = problemDetail.detail;\n }\n \n if (problemDetail.error != null || problemDetail.errors != null) {\n error.error = problemDetail.error ?? problemDetail.errors;\n }\n \n if (problemDetail.title != null) {\n error.title = problemDetail.title;\n }\n \n if (problemDetail.traceId != null) {\n error.traceId = problemDetail.traceId;\n }\n \n if (problemDetail.type != null) {\n error.type = problemDetail.type;\n }\n } else {\n if (typeof response.error === 'string') {\n error.title = response.error;\n } else {\n if (this.isJsonResponse(response)) {\n error.error = JSON.parse(response.error);\n } else {\n error.error = response.error;\n }\n }\n }\n \n return error;\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 d.getFullYear() + '-' +\n n(d.getMonth() + 1) + '-' +\n n(d.getDate()) + 'T' +\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 this.parseDate(value);\n }\n \n return value;\n }\n \n private parseDate(s: string): Date {\n const a = s.split(/[^0-9]/) as any;\n const d = new Date(a[0], a[1] - 1, a[2], a[3], a[4], a[5]);\n return d;\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, this.serializeDate(value));\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 != undefined) {\n params = params.append(name, value);\n }\n }\n }\n }\n \n return params;\n }\n }"; return result; }; AngularGenerator.prototype.getRequestMethod = function (config) { var returnType = config.usePromises ? 'Promise<T>' : 'Observable<T>'; var request = "\n const result = this.http.request(request)\n .pipe(\n filter((event: HttpEvent<any>) => event instanceof HttpResponse),\n map((event: HttpResponse<any>) => {\n return this.extractBody(event);\n }),\n catchError((error: HttpErrorResponse) => {\n return throwError(this.extractError(error));\n })\n );"; var result = "\n protected request<T>(path: string, method: string, urlParams?: any, body?: any): " + returnType + " {\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 " + request + "\n \n return " + (config.usePromises ? 'result.toPromise()' : 'result') + ";\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; var suffix = config.suffix == undefined ? 'Service' : config.suffix; className += suffix; 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