private void WriteInterfaceWithCallToBlock(TypeScriptBlock interfaceWithCallBlock, WebApiAction action, WebApiHttpVerb verb) { var callArguments = action.BodyParameters; var callArgument = callArguments .Select(a => a.GetParameterString(withOptionals: false, interfaceName: true)) .SingleOrDefault(); var callArgumentsList = string.IsNullOrWhiteSpace(callArgument) ? "httpConfig?: angular.IRequestShortcutConfig" : $"{callArgument}, httpConfig?: angular.IRequestShortcutConfig"; string typeScriptReturnType, typeScriptTypeForCall; action.GetReturnTypes(out typeScriptReturnType, out typeScriptTypeForCall); interfaceWithCallBlock .AddStatement($"call{typeScriptTypeForCall}({callArgumentsList}): ng.IPromise{typeScriptReturnType};"); if (Config.EndpointsSupportCaching && verb == WebApiHttpVerb.Get) { interfaceWithCallBlock .AddStatement($"callCached{typeScriptTypeForCall}({callArgumentsList}): ng.IPromise{typeScriptReturnType};"); } }
private void WriteGetQueryStringToBlock(TypeScriptBlock classBlock, string actionName, WebApiAction action) { var queryStringParameters = action.QueryStringParameters; if (!queryStringParameters.Any()) { return; } var queryStringBlock = classBlock .AddAndUseBlock($"{actionName}.prototype.getQueryString = function(): string") .AddStatement("var parameters: string[] = [];"); foreach (var routePart in queryStringParameters) { var argumentName = routePart.Name; var block = queryStringBlock; var argumentType = routePart.GetTypeScriptType(); block.AddStatement($"addParameter(parameters, '{argumentName}', this.{argumentName});"); } queryStringBlock .AddAndUseBlock("if (parameters.length > 0)") .AddStatement("return '?' + parameters.join('&');") .Parent .AddStatement("return '';"); }
public TypeScriptBlock CreateServiceBlock() { var constructorBlock = new TypeScriptBlock($"{Config.NamespaceOrModuleName} {Config.ServiceNamespace}") .AddStatement("type BeforeCallHandler = (endpoint: IEndpoint, data, config: ng.IRequestConfig) => ng.IPromise<void>;") .AddStatement("type AfterCallHandler = <TView> (endpoint: IEndpoint, data, config: ng.IRequestConfig, response: TView) => ng.IPromise<void>;") .AddAndUseBlock($"export class {Config.ServiceName}") .AddStatement("static $inject = ['$http', '$q'];") .AddStatement("static endpointCache = {};", condition: Config.EndpointsSupportCaching) .AddAndUseBlock("constructor($http: ng.IHttpService, $q: ng.IQService)"); var serviceBlock = constructorBlock .Parent .AddAndUseBlock("static call<TView>(httpService: ng.IHttpService, qService: ng.IQService, endpoint: IEndpoint, data, httpConfig?: ng.IRequestShortcutConfig)") .AddAndUseBlock("const config =") .AddStatement("method: endpoint._verb,") .AddStatement("url: endpoint.toString(),") .AddStatement("data: data") .Parent .AddStatement("httpConfig && _.extend(config, httpConfig);") .AddStatement("") .AddAndUseBlock($"return qService.all({Config.ServiceName}.onBeforeCallHandlers.map(onBeforeCall => onBeforeCall.handler(endpoint, data, config))).then(before =>", isFunctionBlock: true, terminationString: ";") .AddStatement($"const call = httpService<TView>(config);") .AddAndUseBlock("return call.then(response =>", isFunctionBlock: true, terminationString: ";") .AddStatement("let result = response.data;") .AddStatement($"return qService.all({Config.ServiceName}.onAfterCallHandlers.map(onAfterCall => onAfterCall.handler<TView>(endpoint, data, config, result))).then(after => result);") .Parent .Parent .Parent .AddStatement("private static onBeforeCallHandlers: ({ name: string; handler: BeforeCallHandler; })[] = []") .AddStatement("private static onAfterCallHandlers: ({ name: string; handler: AfterCallHandler; })[] = []") .AddAndUseBlock("static AddBeforeCallHandler = (name: string, handler: BeforeCallHandler) =>") .AddStatement($"{Config.ServiceName}.onBeforeCallHandlers = _.filter({Config.ServiceName}.onBeforeCallHandlers, h => h.name != name);") .AddStatement($"{Config.ServiceName}.onBeforeCallHandlers.push({{ name: name, handler: handler }});") .AddStatement($"return () => {Config.ServiceName}.onBeforeCallHandlers = _.filter({Config.ServiceName}.onBeforeCallHandlers, h => h.name != name);") .Parent .AddAndUseBlock("static AddAfterCallHandler = (name: string, handler: AfterCallHandler) =>") .AddStatement($"{Config.ServiceName}.onAfterCallHandlers = _.filter({Config.ServiceName}.onAfterCallHandlers, h => h.name != name);") .AddStatement($"{Config.ServiceName}.onAfterCallHandlers.push({{ name: name, handler: handler }});") .AddStatement($"return () => {Config.ServiceName}.onAfterCallHandlers = _.filter({Config.ServiceName}.onAfterCallHandlers, h => h.name != name);") .Parent; if (Config.EndpointsSupportCaching) { serviceBlock .AddAndUseBlock("static callCached<TView>(httpService: ng.IHttpService, qService: ng.IQService, endpoint: IEndpoint, data, httpConfig?: ng.IRequestShortcutConfig)") .AddStatement("var cacheKey = endpoint.toString();") .AddAndUseBlock("if (this.endpointCache[cacheKey] == null)") .AddAndUseBlock("return this.call<TView>(httpService, qService, endpoint, data, httpConfig).then(result =>", isFunctionBlock: true, terminationString: ";") .AddStatement("this.endpointCache[cacheKey] = result;") .AddStatement("return this.endpointCache[cacheKey];") .Parent .Parent .AddStatement("const deferred = qService.defer();") .AddStatement("deferred.resolve(this.endpointCache[cacheKey]);") .AddStatement("return deferred.promise;"); } return(serviceBlock .Parent); }
public TypeScriptBlock CreateEndpointBlock() { var block = new TypeScriptBlock($"{Config.NamespaceOrModuleName} {Config.EndpointsNamespace}"); block .AddAndUseBlock($"export interface {IEndpoint}") .AddStatement("_verb: string;") .AddStatement("toString(): string;") .Parent .AddAndUseBlock("function addParameter(parameters: string[], key: string, value: any)") .AddAndUseBlock("if (value == null)") .AddStatement("return;") .Parent .AddAndUseBlock($"if (_.isArray(value))") .AddStatement($"var encodedItems = _.map(value, (item: any) => encodeURIComponent(item.toString()));") .AddStatement($"_(encodedItems).each(item => parameters.push(`${{key}}=${{item}}`));") .Parent .AddAndUseBlock("else if (_.isObject(value) && value.getQueryParams)") .AddStatement(@"addParameter(parameters, key, value.getQueryParams());") .Parent .AddAndUseBlock("else if (_.isObject(value))") .AddStatement(@"Object.keys(value).forEach((key) => { addParameter(parameters, key, value[key]); });") .Parent .AddAndUseBlock("else") .AddStatement($"parameters.push(`${{key}}=${{encodeURIComponent(value.toString())}}`);"); return(block); }
private void WriteViewEntry(TypeScriptBlock viewsBlock, ViewNode featureViewNode, bool isChild = false) { var namespaceBlock = !isChild ? $"export namespace {featureViewNode.Name}" : $"{featureViewNode.Name} : "; var featureBlock = viewsBlock .AddAndUseBlock(namespaceBlock, terminationString: isChild ? "," : ""); var viewGroup = Config.UseViewsGroupingNamespace && !isChild ? "Views" : string.Empty; if (!string.IsNullOrEmpty(viewGroup)) { featureBlock = featureBlock.AddAndUseBlock($"export var {viewGroup} = "); } foreach (var viewEntry in featureViewNode.ViewEntries) { featureBlock .AddStatement($"{viewEntry.Name} : '{viewEntry.Path}',"); } foreach (var childView in featureViewNode.ChildViews) { WriteViewEntry(featureBlock, childView, isChild: true); } }
private void WriteConstructorToBlock(TypeScriptBlock classBlock, WebApiAction action, WebApiHttpVerb verb) { var actionName = action.GetActionNameForVerb(verb); var constructorParameterMappings = action.GetConstructorParameterMappings(); var areAllParametersOptional = constructorParameterMappings .All(m => m.IsOptional); var optionalString = areAllParametersOptional ? "?" : string.Empty; var constructorBlock = classBlock .AddAndUseBlock($"constructor(args{optionalString}: I{actionName})"); foreach (var mapping in constructorParameterMappings) { constructorBlock .AddStatement($"this.{mapping.Name} = args != null ? args.{mapping.Name} : null;"); if (mapping.TypeMapping?.AutoInitialize ?? false) { constructorBlock .AddAndUseBlock($"if (this.{mapping.Name} == null)") .AddStatement($"this.{mapping.Name} = new {mapping.TypeMapping.TypeScriptTypeName}();"); } } }
public void WriteEndpointClassToBlock(TypeScriptBlock endpointsBlock, WebApiController webApiController) { var controllerBlock = endpointsBlock .AddAndUseBlock($"export {Config.NamespaceOrModuleName} {webApiController.Name}"); var actions = webApiController.Actions.Where(a => a.IsMobileAction); foreach (var action in actions) { if (action.BodyParameters.Count > 1) { LogMessage($"Multiple conflicting call parameters detected in action [{action.Name}] of controller [{webApiController.Name}]!"); LogMessage("Please use [FromBody] or [FromUri] on all non-primitives!"); var parameters = action.BodyParameters.Select(bp => $"[{bp.Name}]"); LogMessage($"Parameters: {string.Join(" ", parameters)}"); LogMessage(""); continue; } foreach (var verb in action.Verbs) { var actionName = action.GetActionNameForVerb(verb); var interfaceBlock = controllerBlock .AddAndUseBlock($"export interface I{actionName}"); WriteInterfaceToBlock(interfaceBlock, action); var endpointBlock = controllerBlock .AddAndUseBlock($"export interface I{actionName}Endpoint extends I{actionName}, IEndpoint"); var ctorBlock = controllerBlock .AddAndUseBlock($"export interface I{actionName}Ctor") .AddStatement($"new(args?: I{actionName}): I{actionName}Endpoint"); var ctorImplBlock = controllerBlock .AddAndUseBlock($"export var {actionName} : I{actionName}Ctor = <any>(function(args?: I{actionName})", false, ");") .AddStatement($"this._verb = '{verb.VerbMethod}';"); var constructorParameterMappings = action.GetConstructorParameterMappings(ignoreEnumDefinitions: true); foreach (var mapping in constructorParameterMappings) { ctorImplBlock.AddStatement($"this.{mapping.Name} = args != null ? args.{mapping.Name} : null;"); if (mapping.TypeMapping?.AutoInitialize ?? false) { ctorImplBlock .AddAndUseBlock($"if (this.{mapping.Name} == null)") .AddStatement($"this.{mapping.Name} = new {mapping.TypeMapping.TypeScriptTypeName}();"); } } WriteGetQueryStringToBlock(controllerBlock, actionName, action); WriteToStringToBlock(controllerBlock, actionName, action); } } }
public TypeScriptBlock WriteViewsToBlock(List <ViewNode> featureViews, TypeScriptBlock viewsBlock) { foreach (var featureView in featureViews) { WriteViewEntry(viewsBlock, featureView); } return(viewsBlock); }
public TypeScriptBlock WriteEnumsToBlock(TypeScriptBlock enumsBlock) { foreach (var typeDefinition in Enums) { CreateEnumForType(enumsBlock, typeDefinition); } return(enumsBlock); }
public void WriteEndpointClassToBlock(TypeScriptBlock endpointBlock, WebApiController webApiController) { var controllerBlock = endpointBlock .AddAndUseBlock($"export {Config.NamespaceOrModuleName} {webApiController.Name}"); TypeScriptBlock serviceBlock = null; if (Config.GenerateService) { serviceBlock = controllerBlock .AddAndUseBlock($"export interface I{webApiController.Name}Service"); } var actions = webApiController.Actions; foreach (var action in actions) { foreach (var verb in action.Verbs) { var actionName = action.GetActionNameForVerb(verb); var interfaceBlock = controllerBlock .AddAndUseBlock($"export interface I{actionName}"); WriteInterfaceToBlock(interfaceBlock, action); if (Config.GenerateService) { var interfaceWithCallBlock = controllerBlock .AddAndUseBlock($"export interface I{actionName}WithCall extends I{actionName}, {IEndpoint}"); WriteInterfaceWithCallToBlock(interfaceWithCallBlock, action, verb); serviceBlock .AddStatement($"{actionName}: (args?: I{actionName}) => I{actionName}WithCall"); } var classBlock = controllerBlock .AddAndUseBlock($"export class {actionName} implements I{actionName}, {IEndpoint}") .AddStatement($"_verb = '{verb.VerbMethod}';"); var constructorParameterMappings = action.GetConstructorParameterMappings(); foreach (var constructorParameterMapping in constructorParameterMappings) { classBlock .AddStatement($"{constructorParameterMapping.String};"); } WriteConstructorToBlock(classBlock, action, verb); WriteGetQueryStringToBlock(classBlock, action); WriteToStringToBlock(classBlock, action); } } }
private void WriteInterfaceToBlock(TypeScriptBlock interfaceBlock, WebApiAction action) { var constructorParameterMappings = action.GetConstructorParameterMappings(); foreach (var constructorParameterMapping in constructorParameterMappings) { interfaceBlock .AddStatement($"{constructorParameterMapping.StringWithOptionals};"); } }
public TypeScriptBlock CreateServiceBlock() { var serviceBlock = new TypeScriptBlock($"{Config.NamespaceOrModuleName} {Config.ServiceNamespace}") .AddAndUseBlock($"export class {Config.ServiceName}") .AddStatement ( Config.EndpointsSupportCaching ? "static $inject = ['$http', '$q'];" : "static $inject = ['$http'];" ) .AddStatement("static $http: ng.IHttpService;") .AddStatement("static $q: ng.IQService;", condition: Config.EndpointsSupportCaching) .AddStatement("static endpointCache = {};", condition: Config.EndpointsSupportCaching) .AddAndUseBlock ( Config.EndpointsSupportCaching ? "constructor($http: ng.IHttpService, $q: ng.IQService)" : "constructor($http: ng.IHttpService)" ) .AddStatement($"{Config.ServiceName}.$http = $http;") .AddStatement($"{Config.ServiceName}.$q = $q;", condition: Config.EndpointsSupportCaching) .Parent .AddAndUseBlock("static call<TView>(endpoint: IEndpoint, data, httpConfig?: angular.IRequestShortcutConfig)") .AddAndUseBlock("const config = ") .AddStatement("method: endpoint._verb,") .AddStatement("url: endpoint.toString(),") .AddStatement("data: data") .Parent .AddStatement("httpConfig && _.extend(config, httpConfig);") .AddStatement("") .AddStatement($"const call = {Config.ServiceName}.$http<TView>(config);") .AddStatement("return call.then(response => response.data);"); if (Config.EndpointsSupportCaching) { serviceBlock .Parent .AddAndUseBlock("static callCached<TView>(endpoint: IEndpoint, data, httpConfig?: angular.IRequestShortcutConfig)") .AddStatement("var cacheKey = endpoint.toString();") .AddAndUseBlock("if (this.endpointCache[cacheKey] == null)") .AddAndUseBlock("return this.call<TView>(endpoint, data, httpConfig).then(result =>", isFunctionBlock: true, terminationString: ";") .AddStatement("this.endpointCache[cacheKey] = result;") .AddStatement("return this.endpointCache[cacheKey];") .Parent .Parent .AddStatement("const deferred = this.$q.defer();") .AddStatement("deferred.resolve(this.endpointCache[cacheKey]);") .AddStatement("return deferred.promise;"); } return(serviceBlock .Parent .Parent); }
private void WriteToStringToBlock(TypeScriptBlock classBlock, WebApiAction action) { var toStringBlock = classBlock .AddAndUseBlock("toString = (): string =>"); var queryString = action.QueryStringParameters.Any() ? " + this.getQueryString()" : string.Empty; toStringBlock .AddStatement($"return `{action.Controller.BaseEndpoint}{action.Endpoint}`{queryString};"); }
private void CreateFileForBlock(TypeScriptBlock typeScriptBlock, string outputDirectory, string fileName) { LogMessage($"Writing {fileName}..."); CreateOuputDirectory(outputDirectory); var filePath = Path.Combine(outputDirectory, fileName); using (var endpointFileWriter = new StreamWriter(filePath, false)) { endpointFileWriter.Write(typeScriptBlock.ToString()); } }
private void WriteInterfaceWithCallToBlock(TypeScriptBlock interfaceWithCallBlock, WebApiAction action) { var callArguments = action.BodyParameters; var callArgumentStrings = callArguments .Select(a => a.GetParameterString(withOptionals: false, interfaceName: true)) .SingleOrDefault(); var callArgumentsList = string.Join(", ", callArgumentStrings); interfaceWithCallBlock .AddStatement($"call<TView>({callArgumentsList}): ng.IPromise<TView>;"); }
private void CreateEnumForType(TypeScriptBlock enumsBlock, TypeDefinition typeDefinition) { var fields = typeDefinition.Fields .Where(f => f.HasConstant && !f.IsSpecialName); var enumBlock = enumsBlock .AddAndUseBlock($"export enum {typeDefinition.Name}"); foreach (var field in fields) { enumBlock.AddStatement($"{field.Name} = {field.Constant},"); } }
public void WriteServiceObjectToBlock(TypeScriptBlock serviceBlock, WebApiController webApiController) { var controllerBlock = serviceBlock .AddAndUseBlock($"public {webApiController.Name} ="); var actions = webApiController.Actions; for (var a = 0; a < actions.Count; a++) { var action = actions[a]; var constructorParameterMappings = action.GetConstructorParameterMappings(); for (var v = 0; v < action.Verbs.Count; v++) { var verb = action.Verbs[v]; var actionName = action.GetActionNameForVerb(verb); var isLastActionAndVerb = a == actions.Count - 1 && v == action.Verbs.Count - 1; var areAllParametersOptional = constructorParameterMappings .All(m => m.IsOptional); var optionalString = areAllParametersOptional ? "?" : string.Empty; var callArgumentDefinition = action.GetCallArgumentDefinition(verb); var callArgumentValue = action.GetCallArgumentValue(verb); var interfaceFullName = $"{Config.EndpointsNamespace}.{webApiController.Name}.I{actionName}"; var interfaceWithCallFullName = $"{Config.EndpointsNamespace}.{webApiController.Name}.I{actionName}WithCall"; var endpointFullName = $"{Config.EndpointsNamespace}.{webApiController.Name}.{actionName}"; controllerBlock .AddAndUseBlock ( outer: $"{actionName}: (args{optionalString}: {interfaceFullName}): {interfaceWithCallFullName} =>", isFunctionBlock: false, terminationString: !isLastActionAndVerb ? "," : string.Empty ) .AddStatement($"var endpoint = new {endpointFullName}(args);") .AddAndUseBlock("return _.extendOwn(endpoint,", isFunctionBlock: true, terminationString: ";") .AddAndUseBlock($"call<TView>({callArgumentDefinition})") .AddStatement($"return {Config.ServiceName}.call<TView>(this, {callArgumentValue});"); } } }
private void WriteInterfaces(TypeScriptBlock interfacesBlock, InterfaceNode interfaceNode) { var typeDefinition = interfaceNode.TypeDefinition; if (typeDefinition != null) { WriteInterfaceNode(interfacesBlock, interfaceNode); } foreach (var derivedInterfaceNode in interfaceNode.DerivedInterfaces) { WriteInterfaces(interfacesBlock, derivedInterfaceNode); } }
private void CreateFileForBlock(TypeScriptBlock typeScriptBlock, string outputDirectory, string fileName) { CreateOuputDirectory(outputDirectory); var filePath = Path.Combine(outputDirectory, fileName); //LogMessage($"Writing file [{filePath}]..."); //stopwatch = Stopwatch.StartNew(); using (var endpointFileWriter = new StreamWriter(filePath, false)) { endpointFileWriter.Write(typeScriptBlock.ToString()); } //LogMessage($"File [{filePath}] saved! Took {stopwatch.ElapsedMilliseconds}ms."); }
private void CreateGetDescriptionExtensionForType(TypeScriptBlock enumsBlock, TypeDefinition typeDefinition) { var fields = typeDefinition.Fields .Where(f => f.HasConstant && !f.IsSpecialName); var switchBlock = enumsBlock .AddAndUseBlock($"export namespace {typeDefinition.Name}") .AddAndUseBlock($"export function getDescription(enumValue: {typeDefinition.Name})") .AddAndUseBlock("switch (enumValue)"); foreach (var field in fields) { var fieldDescription = GetFieldDescription(field); switchBlock .AddStatement($"case {typeDefinition.Name}.{field.Name}: return \"{fieldDescription}\";"); } }
private void WriteViewEntry(TypeScriptBlock viewsBlock, ViewNode featureViewNode, bool isChild = false) { var viewNamespace = Config.UseViewsGroupingNamespace && !isChild ? ".Views" : string.Empty; var featureBlock = viewsBlock .AddAndUseBlock($"export namespace {featureViewNode.Name}{viewNamespace}"); foreach (var viewEntry in featureViewNode.ViewEntries) { featureBlock .AddStatement($"export const {viewEntry.Name} = '{viewEntry.Path}';"); } foreach (var childView in featureViewNode.ChildViews) { WriteViewEntry(featureBlock, childView, isChild: true); } }
public TypeScriptBlock WriteEnumsToBlock(TypeScriptBlock enumsBlock) { var sortedEnums = Enums .OrderBy(e => e.Name); foreach (var typeDefinition in sortedEnums) { WriteEnumForType(enumsBlock, typeDefinition); if (Config.GenerateEnumDescriptions) { CreateGetDescriptionExtensionForType(enumsBlock, typeDefinition); } } foreach (var logMessage in LogMessages) { LogMessage(logMessage.Value); } return(enumsBlock); }
private void WriteGetQueryStringToBlock(TypeScriptBlock classBlock, WebApiAction action) { var queryStringParameters = action.QueryStringParameters; if (!queryStringParameters.Any()) { return; } var queryStringBlock = classBlock .AddAndUseBlock("private getQueryString = (): string =>") .AddStatement("var parameters: string[] = [];"); foreach (var routePart in queryStringParameters) { var argumentName = routePart.Name; var block = queryStringBlock; var argumentType = routePart.GetTypeScriptType(); if (argumentType.IsPrimitive || argumentType.IsEnum) { block .AddStatement($"addParameter(parameters, '{argumentName}', this.{argumentName});"); } else { block .AddStatement($"addObjectParameters(parameters, this.{argumentName});"); } } queryStringBlock .AddAndUseBlock("if (parameters.length > 0)") .AddStatement("return '?' + parameters.join('&');") .Parent .AddStatement("return '';"); }
public TypeScriptBlock WriteInterfacesToBlock(TypeScriptBlock interfacesBlock) { WriteInterfaces(interfacesBlock, InterfaceNode); return(interfacesBlock); }
private void WriteInterfaceNode(TypeScriptBlock interfacesBlock, InterfaceNode interfaceNode) { var typeDefinition = interfaceNode.TypeDefinition; string implementsString = null; string extendsString = null; var iHaveGenericParameters = typeDefinition.HasGenericParameters; if (iHaveGenericParameters) { var genericParameters = typeDefinition.GenericParameters .Select(p => p.Name); implementsString = WrapInAngledBrackets(string.Join(", ", genericParameters)); } var hasBaseClass = interfaceNode.BaseInterface?.TypeDefinition != null; var baseTypeName = CleanName(interfaceNode.BaseInterface?.TypeDefinition?.Name); if (hasBaseClass) { var iHaveGenericArguments = typeDefinition.BaseType.IsGenericInstance; if (iHaveGenericArguments) { var baseTypeInstance = typeDefinition.BaseType as GenericInstanceType; var genericArguments = baseTypeInstance.GenericArguments .Select(p => p.IsGenericParameter ? p.Name : TypeService.GetTypeScriptType(p.GetElementType(), p.Name).TypeName); extendsString = WrapInAngledBrackets(string.Join(", ", genericArguments)); } var baseTypeHasGenericParameters = typeDefinition.BaseType.HasGenericParameters; if (baseTypeHasGenericParameters) { var genericParameters = typeDefinition.BaseType.GenericParameters .Select(p => p.Name); extendsString = WrapInAngledBrackets(string.Join(", ", genericParameters)); } } var interfaceExtendsString = hasBaseClass ? $" extends I{baseTypeName}{extendsString}" : string.Empty; var classExtendsString = hasBaseClass ? $" extends {baseTypeName}{extendsString}" : string.Empty; var blockTypeName = CleanName(typeDefinition.Name); if (!TypeService.IsValidTypeName(blockTypeName)) { LogMessage($"Interface name [{blockTypeName}] of type [{typeDefinition.FullName}] is invalid!"); return; } var classImplementsString = $" implements I{blockTypeName}{implementsString}"; var parameterOrInstanceString = iHaveGenericParameters ? implementsString : string.Empty; var interfaceBlock = interfacesBlock .AddAndUseBlock($"export interface I{blockTypeName}{parameterOrInstanceString}{interfaceExtendsString}"); TypeScriptBlock classBlock = null; if (Config.GenerateInterfaceClasses) { classBlock = interfacesBlock .AddAndUseBlock($"export class {blockTypeName}{parameterOrInstanceString}{classExtendsString}{classImplementsString}"); } var things = GetMembers(typeDefinition); foreach (var thing in things) { var thingType = thing.CSharpType.TypeDefinition; var union = SameNamedDerivedMembers(thing, interfaceNode) .Select(e => e.CSharpType.TypeDefinition) .ToList(); union.Add(thingType); string interfaceName; string typeName; if (thing.CSharpType.IsGenericParameter) { typeName = interfaceName = thing.CSharpType.GenericParameterName; } else { if (thingType.IsInterface) { continue; } if (union.Count == 1) { var typeScriptType = TypeService.GetTypeScriptType(union[0], thing.Name); interfaceName = typeScriptType.InterfaceName; typeName = typeScriptType.TypeName; } else { typeName = string.Join(" | ", union .Select(t => { var type = TypeService.GetTypeScriptType(t, thing.Name); return(type.TypeName); }) .Distinct()); interfaceName = string.Join(" | ", union .Select(t => { var type = TypeService.GetTypeScriptType(t, thing.Name); return(type.InterfaceName); }).Distinct()); } } var thingName = Config.InterfaceMembersInCamelCase ? Helpers.ToCamelCaseFromPascalCase(thing.Name) : thing.Name; var collectionString = thing.CSharpType.IsCollection ? "[]" : string.Empty; thingName = TypeService.FixIfReservedWord(thingName); interfaceBlock .AddStatement($"{thingName}: {interfaceName}{collectionString};"); if (Config.GenerateInterfaceClasses) { classBlock .AddStatement($"{thingName}: {typeName}{collectionString};"); } } if (Config.GenerateInterfaceClasses) { if (hasBaseClass) { classBlock .AddAndUseBlock("constructor()") .AddStatement("super();"); } } }
private void WriteInterfaces(TypeScriptBlock interfacesBlock, InterfaceNode interfaceNode) { var typeDefinition = interfaceNode.TypeDefinition; if (typeDefinition != null) { string implementsString = null; string extendsString = null; var iHaveGenericParameters = typeDefinition.HasGenericParameters; if (iHaveGenericParameters) { var genericParameters = typeDefinition.GenericParameters .Select(p => p.Name); implementsString = WrapInAngledBrackets(string.Join(", ", genericParameters)); } var hasBaseClass = interfaceNode.BaseInterface?.TypeDefinition != null; var baseTypeName = CleanName(interfaceNode.BaseInterface?.TypeDefinition?.Name); if (hasBaseClass) { var iHaveGenericArguments = typeDefinition.BaseType.IsGenericInstance; if (iHaveGenericArguments) { var baseTypeInstance = typeDefinition.BaseType as GenericInstanceType; var genericArguments = baseTypeInstance.GenericArguments .Select(p => p.IsGenericParameter ? p.Name : TypeService.GetTypeScriptType(p.GetElementType(), p.Name).TypeName); extendsString = WrapInAngledBrackets(string.Join(", ", genericArguments)); } var baseTypeHasGenericParameters = typeDefinition.BaseType.HasGenericParameters; if (baseTypeHasGenericParameters) { var genericParameters = typeDefinition.BaseType.GenericParameters .Select(p => p.Name); extendsString = WrapInAngledBrackets(string.Join(", ", genericParameters)); } } var interfaceExtendsString = hasBaseClass ? $" extends I{baseTypeName}{extendsString}" : string.Empty; var classExtendsString = hasBaseClass ? $" extends {baseTypeName}{extendsString}" : string.Empty; var blockTypeName = CleanName(typeDefinition.Name); var classImplementsString = $" implements I{blockTypeName}{implementsString}, {Config.EndpointsNamespace}.{nameof(IHaveQueryParams)}"; var parameterOrInstanceString = iHaveGenericParameters ? implementsString : string.Empty; var interfaceBlock = interfacesBlock .AddAndUseBlock($"export interface I{blockTypeName}{parameterOrInstanceString}{interfaceExtendsString}"); var classBlock = interfacesBlock .AddAndUseBlock($"export class {blockTypeName}{parameterOrInstanceString}{classExtendsString}{classImplementsString}"); var things = GetMembers(typeDefinition); foreach (var thing in things) { var interfaceName = string.Empty; var typeName = string.Empty; if (thing.CSharpType.IsGenericParameter) { typeName = interfaceName = thing.CSharpType.GenericParameterName; } else { var thingType = thing.CSharpType.TypeDefinition; var typeScriptType = TypeService.GetTypeScriptType(thingType, thing.Name); interfaceName = typeScriptType.InterfaceName; typeName = typeScriptType.TypeName; } var thingName = Config.InterfaceMembersInCamelCase ? Helpers.ToCamelCaseFromPascalCase(thing.Name) : thing.Name; var collectionString = thing.CSharpType.IsCollection ? "[]" : string.Empty; interfaceBlock .AddStatement($"{thingName}: {interfaceName}{collectionString};"); classBlock .AddStatement($"{thingName}: {typeName}{collectionString};"); } if (hasBaseClass) { classBlock .AddAndUseBlock("constructor()") .AddStatement("super();"); } classBlock .AddAndUseBlock("getQueryParams()") .AddStatement("return this;"); } foreach (var derivedInterfaceNode in interfaceNode.DerivedInterfaces) { WriteInterfaces(interfacesBlock, derivedInterfaceNode); } }
public void WriteServiceObjectToBlock(TypeScriptBlock serviceBlock, WebApiController webApiController) { var constructorBlock = serviceBlock.Children .OfType <TypeScriptBlock>() .First(); var controllerBlock = serviceBlock .AddStatement($"public {webApiController.Name}: {Config.EndpointsNamespace}.{webApiController.Name}.I{webApiController.Name}Service = <any>{{}};"); var actions = webApiController.Actions; foreach (var action in actions) { if (action.BodyParameters.Count > 1) { continue; } var constructorParameterMappings = action.GetConstructorParameterMappings(); foreach (var verb in action.Verbs) { var actionName = action.GetActionNameForVerb(verb); var areAllParametersOptional = constructorParameterMappings .All(m => m.IsOptional); var optionalString = areAllParametersOptional ? "?" : string.Empty; var callArgumentDefinition = action.GetCallArgumentDefinition(verb); var callArgumentValue = action.GetCallArgumentValue(verb); var interfaceFullName = $"{Config.EndpointsNamespace}.{webApiController.Name}.I{actionName}"; var interfaceWithCallFullName = $"{Config.EndpointsNamespace}.{webApiController.Name}.I{actionName}WithCall"; var endpointFullName = $"{Config.EndpointsNamespace}.{webApiController.Name}.{actionName}"; string typeScriptReturnType, typeScriptTypeForCall; action.GetReturnTypes(out typeScriptReturnType, out typeScriptTypeForCall); var endpointExtendBlock = constructorBlock .AddAndUseBlock ( outer: $"this.{webApiController.Name}.{actionName} = (args{optionalString}: {interfaceFullName}): {interfaceWithCallFullName} =>", isFunctionBlock: false, terminationString: ";" ) .AddStatement($"var endpoint = new {endpointFullName}(args);") .AddAndUseBlock("return _.extendOwn(endpoint,", isFunctionBlock: true, terminationString: ";") .AddAndUseBlock ( outer: $"call{typeScriptTypeForCall}({callArgumentDefinition})", isFunctionBlock: false, terminationString: Config.EndpointsSupportCaching ? "," : string.Empty ) .AddStatement($"return {Config.ServiceName}.call{typeScriptReturnType}($http, $q, this, {callArgumentValue});") .Parent; if (Config.EndpointsSupportCaching && verb == WebApiHttpVerb.Get) { endpointExtendBlock.AddAndUseBlock($"callCached{typeScriptTypeForCall}({callArgumentDefinition})") .AddStatement($"return {Config.ServiceName}.callCached{typeScriptReturnType}($http, $q, this, {callArgumentValue});"); } } } }
private void WriteInterfaceNode(TypeScriptBlock interfacesBlock, InterfaceNode interfaceNode) { var typeDefinition = interfaceNode.TypeDefinition; string implementsString = null; string _interfaceExtendsString = null; string _classExtendsString = null; var iHaveGenericParameters = typeDefinition.HasGenericParameters; if (iHaveGenericParameters) { var genericParameters = typeDefinition.GenericParameters .Select(p => p.Name); implementsString = WrapInAngledBrackets(string.Join(", ", genericParameters)); } var hasBaseClass = interfaceNode.BaseInterface?.TypeDefinition != null; var baseTypeName = TypeService.CleanGenericName(interfaceNode.BaseInterface?.TypeDefinition?.Name); var things = GetMembers(typeDefinition); if (hasBaseClass) { if (typeDefinition.BaseType is GenericInstanceType baseTypeInstance) { var classGenericArguments = baseTypeInstance.GenericArguments .Select(p => p.IsGenericParameter ? p.Name : TypeService.GetTypeScriptType(p.GetElementType(), p.Name).TypeName); var interfaceGenericArguments = baseTypeInstance.GenericArguments .Select(p => p.IsGenericParameter ? p.Name : TypeService.GetTypeScriptType(p.GetElementType(), p.Name).InterfaceName); _classExtendsString = WrapInAngledBrackets(string.Join(", ", classGenericArguments)); _interfaceExtendsString = WrapInAngledBrackets(string.Join(", ", interfaceGenericArguments)); } else { var baseTypeHasGenericParameters = typeDefinition.BaseType.HasGenericParameters; if (baseTypeHasGenericParameters) { var genericParameters = typeDefinition.BaseType.GenericParameters .Select(p => p.Name); _classExtendsString = _interfaceExtendsString = WrapInAngledBrackets(string.Join(", ", genericParameters)); } } } var interfaceExtendsString = hasBaseClass ? $" extends I{baseTypeName}{_interfaceExtendsString}" : string.Empty; var classExtendsString = hasBaseClass ? $" extends {baseTypeName}{_classExtendsString}" : string.Empty; var blockTypeName = TypeService.CleanGenericName(typeDefinition.Name); if (!TypeService.IsValidTypeName(blockTypeName)) { LogMessage($"Interface name [{blockTypeName}] of type [{typeDefinition.FullName}] is invalid!"); return; } var classImplementsString = $" implements I{blockTypeName}{implementsString}"; var parameterOrInstanceString = iHaveGenericParameters ? implementsString : string.Empty; var interfaceBlock = interfacesBlock .AddAndUseBlock($"export interface I{blockTypeName}{parameterOrInstanceString}{interfaceExtendsString}"); TypeScriptBlock classBlock = null; if (Config.GenerateInterfaceClasses) { classBlock = interfacesBlock .AddAndUseBlock($"export class {blockTypeName}{parameterOrInstanceString}{classExtendsString}{classImplementsString}"); } foreach (var thing in things) { var thingType = thing.CSharpType.TypeDefinition; var union = SameNamedDerivedMembers(thing, interfaceNode) .Select(e => e.CSharpType.TypeDefinition) .ToList(); union.Add(thingType); string interfaceName; string typeName; if (thing.CSharpType.IsGenericParameter) { typeName = interfaceName = thing.CSharpType.GenericParameterName; } else if (thing.CSharpType.IsGenericInstance) { var baseTypeScriptType = TypeService.GetTypeScriptType(thing.CSharpType.TypeDefinition, thing.Name); if (baseTypeScriptType.IsMappedType) { typeName = baseTypeScriptType.TypeName; interfaceName = baseTypeScriptType.InterfaceName; } else { var typeNames = string.Join(", ", thing.CSharpType.GenericArgumentTypes .Select(t => { var genericArgumentTypeScriptType = TypeService.GetTypeScriptType(t, thing.Name); return(genericArgumentTypeScriptType.TypeName); })); var interfaceNames = string.Join(", ", thing.CSharpType.GenericArgumentTypes .Select(t => { var genericArgumentTypeScriptType = TypeService.GetTypeScriptType(t, thing.Name); return(genericArgumentTypeScriptType.InterfaceName); })); typeName = $"{baseTypeScriptType.TypeName}<{typeNames}>"; interfaceName = $"{baseTypeScriptType.InterfaceName}<{interfaceNames}>"; } } else { if (thingType.IsInterface) { continue; } if (union.Count == 1) { var typeScriptType = TypeService.GetTypeScriptType(union[0], thing.Name); typeName = typeScriptType.TypeName; interfaceName = typeScriptType.InterfaceName; } else { typeName = string.Join(" | ", union .Select(t => { var type = TypeService.GetTypeScriptType(t, thing.Name); return(type.TypeName); }) .Distinct()); interfaceName = string.Join(" | ", union .Select(t => { var type = TypeService.GetTypeScriptType(t, thing.Name); return(type.InterfaceName); }).Distinct()); } } var thingName = thing.Name; var jsonProperty = thing.CustomAttributes.SingleOrDefault(a => a.AttributeType.Name == "JsonPropertyAttribute"); if (jsonProperty != null) { try { thingName = jsonProperty?.HasProperties ?? false ? jsonProperty.Properties.Single(p => p.Name == "PropertyName").Argument.Value.ToString() : jsonProperty?.HasConstructorArguments ?? false ? jsonProperty.ConstructorArguments.Single().Value.ToString() : thing.Name; } catch { // This is to suppress a assembly load execption which I am unsure of why it is happening } } if (Config.InterfaceMembersInCamelCase || typeDefinition.CustomAttributes.Any(a => a.AttributeType.Name == Config.InterfaceCamelCaseCustomAttribute)) { thingName = Helpers.ToCamelCaseFromPascalCase(thingName); } var collectionString = Helpers.GetCollectionPostfix(thing.CSharpType.CollectionLevel); thingName = TypeService.FixIfReservedWord(thingName); interfaceBlock .AddStatement($"{thingName}: {interfaceName}{collectionString};"); if (Config.GenerateInterfaceClasses) { classBlock .AddStatement($"{thingName}: {typeName}{collectionString};"); } } if (Config.GenerateInterfaceClasses) { if (hasBaseClass) { classBlock .AddAndUseBlock("constructor()") .AddStatement("super();"); } } }