webapi-ng2
Version:
ASP.NET Core Web API client generator for Angular 2
321 lines • 24.2 kB
JavaScript
"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