public void GetImportsText_TypeGiven_ImportsTextGenerated(Type type, string outputDir, TypeNameConverterCollection fileNameConverters, TypeNameConverterCollection typeNameConverters, IEnumerable <object> typeDependencies, string expectedOutput) { //arrange var generatorOptionsProvider = new GeneratorOptionsProvider { GeneratorOptions = new GeneratorOptions { FileNameConverters = fileNameConverters, TypeNameConverters = typeNameConverters } }; _typeDependencyService.GetTypeDependencies(Arg.Any <Type>()).Returns(typeDependencies); _templateService.FillImportTemplate(Arg.Any <string>(), Arg.Any <string>(), Arg.Any <string>()).Returns(i => $"{i.ArgAt<string>(0)} | {i.ArgAt<string>(1)} | {i.ArgAt<string>(2)};"); var tsContentGenerator = new TsContentGenerator(_typeDependencyService, _typeService, _templateService, _tsContentParser, _metadataReaderFactory, generatorOptionsProvider, null); //act string actualOutput = tsContentGenerator.GetImportsText(type, outputDir); //assert Assert.Equal(expectedOutput, actualOutput); }
/// <summary> /// Returns TypeScript imports source code related to type dependencies /// </summary> /// <param name="type"></param> /// <param name="outputDir"></param> /// <param name="fileNameConverters"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> private string GetTypeDependencyImportsText(Type type, string outputDir, TypeNameConverterCollection fileNameConverters, TypeNameConverterCollection typeNameConverters) { var result = ""; IEnumerable <TypeDependencyInfo> typeDependencies = _typeDependencyService.GetTypeDependencies(type); foreach (TypeDependencyInfo typeDependencyInfo in typeDependencies) { Type typeDependency = typeDependencyInfo.Type; string dependencyOutputDir = GetTypeDependencyOutputDir(typeDependencyInfo, outputDir); // get path diff string pathDiff = _fileSystem.GetPathDiff(outputDir, dependencyOutputDir); pathDiff = pathDiff.StartsWith("..\\") || pathDiff.StartsWith("../") ? pathDiff : $"./{pathDiff}"; // get type & file name string typeDependencyName = typeDependency.Name.RemoveTypeArity(); string fileName = fileNameConverters.Convert(typeDependencyName, typeDependency); // get file path string dependencyPath = pathDiff + fileName; dependencyPath = dependencyPath.Replace('\\', '/'); string typeName = typeNameConverters.Convert(typeDependencyName, typeDependency); result += _templateService.FillImportTemplate(typeName, "", dependencyPath); } return(result); }
/// <summary> /// Gets TypeScript type name for a dictionary type /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> private string GetTsDictionaryTypeName(Type type, TypeNameConverterCollection typeNameConverters) { // handle IDictionary<,> Type dictionary2Interface = type.GetInterface("System.Collections.Generic.IDictionary`2"); if (dictionary2Interface != null || (type.FullName != null && type.FullName.StartsWith("System.Collections.Generic.IDictionary`2"))) { Type dictionaryType = dictionary2Interface ?? type; Type keyType = dictionaryType.GetGenericArguments()[0]; Type valueType = dictionaryType.GetGenericArguments()[1]; string keyTypeName = GetTsTypeName(keyType, typeNameConverters); string valueTypeName = GetTsTypeName(valueType, typeNameConverters); if (!keyTypeName.In("number", "string")) { throw new CoreException($"Error when determining TypeScript type for C# type '{type.FullName}':" + " TypeScript dictionary key type must be either 'number' or 'string'"); } return(GetTsDictionaryTypeText(keyTypeName, valueTypeName)); } // handle IDictionary if (type.GetInterface("System.Collections.IDictionary") != null || (type.FullName != null && type.FullName.StartsWith("System.Collections.IDictionary"))) { return(GetTsDictionaryTypeText("string", "string")); } return(null); }
/// <summary> /// Gets TypeScript type name for a generic type - used in type declarations /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> private string GetGenericTsTypeNameForDeclaration(Type type, TypeNameConverterCollection typeNameConverters) { return(GetGenericTsTypeNameDeclarationAgnostic(type, typeNameConverters, t => t.GetTypeInfo().BaseType != null && t.GetTypeInfo().BaseType != typeof(object) ? $"{t.Name} extends {GetTsTypeName(t.GetTypeInfo().BaseType, typeNameConverters, true)}" : t.Name)); }
/// <summary> /// Gets code for the 'imports' section for a given type /// </summary> /// <param name="type"></param> /// <param name="outputDir"></param> /// <param name="fileNameConverters"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> /// <exception cref="ArgumentNullException">Thrown when one of: type, fileNameConverters or typeNameConverters is null</exception> public string GetImportsText(Type type, string outputDir, TypeNameConverterCollection fileNameConverters, TypeNameConverterCollection typeNameConverters) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (fileNameConverters == null) { throw new ArgumentNullException(nameof(fileNameConverters)); } if (typeNameConverters == null) { throw new ArgumentNullException(nameof(typeNameConverters)); } string result = GetTypeDependencyImportsText(type, outputDir, fileNameConverters, typeNameConverters); result += GetCustomImportsText(type); if (!string.IsNullOrEmpty(result)) { result += "\r\n"; } return(result); }
private string GetGenericTsTypeNameDeclarationAgnostic(Type type, TypeNameConverterCollection typeNameConverters, Func <Type, string> genericArgumentsSelector) { string[] genericArgumentNames = type.GetGenericArguments() .Select(genericArgumentsSelector) .ToArray(); string typeName = type.Name.RemoveTypeArity(); string genericArgumentDef = string.Join(", ", genericArgumentNames); return($"{typeNameConverters.Convert(typeName, type)}<{genericArgumentDef}>"); }
/// <summary> /// Gets TypeScript type name for a generic (not generic definition) type /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> private string GetGenericNonDefinitionTsTypeName(Type type, TypeNameConverterCollection typeNameConverters) { string[] genericArgumentNames = type.GetGenericArguments() .Select(t => t.IsGenericParameter ? t.Name : GetTsTypeName(t, typeNameConverters)) .ToArray(); string typeName = type.Name.RemoveTypeArity(); string genericArgumentDef = string.Join(", ", genericArgumentNames); return($"{typeNameConverters.Convert(typeName, type)}<{genericArgumentDef}>"); }
/// <summary> /// Gets TypeScript type name for a generic type /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <param name="isMember"></param> /// <returns></returns> private string GetGenericTsTypeName(Type type, TypeNameConverterCollection typeNameConverters, bool isMember = false) { if (isMember) { return(GetGenericNonDefinitionTsTypeName(type, typeNameConverters)); } return(type.GetTypeInfo().IsGenericTypeDefinition ? GetGenericDefinitionTsTypeName(type, typeNameConverters) : GetGenericNonDefinitionTsTypeName(type, typeNameConverters)); }
/// <summary> /// Gets TypeScript type name for a generic type /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <param name="forTypeDeclaration"></param> /// <returns></returns> private string GetGenericTsTypeName(Type type, TypeNameConverterCollection typeNameConverters, bool forTypeDeclaration = false) { if (!forTypeDeclaration) { return(GetGenericTsTypeNameForNonDeclaration(type, typeNameConverters)); } return(type.GetTypeInfo().IsGenericTypeDefinition ? GetGenericTsTypeNameForDeclaration(type, typeNameConverters) : GetGenericTsTypeNameForNonDeclaration(type, typeNameConverters)); }
/// <summary> /// Gets TypeScript type name for a generic definition type /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> private string GetGenericDefinitionTsTypeName(Type type, TypeNameConverterCollection typeNameConverters) { Type[] genericArguments = type.GetGenericArguments(); string[] genericArgumentNames = (from t in genericArguments select t.GetTypeInfo().BaseType != null && t.GetTypeInfo().BaseType != typeof(object) ? $"{t.Name} extends {GetTsTypeName(t.GetTypeInfo().BaseType, typeNameConverters)}" : t.Name) .ToArray(); string typeName = type.Name.RemoveTypeArity(); string genericArgumentDef = string.Join(", ", genericArgumentNames); return($"{typeNameConverters.Convert(typeName, type)}<{genericArgumentDef}>"); }
/// <summary> /// Gets TypeScript type name for a member /// </summary> /// <param name="memberInfo"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> /// <exception cref="ArgumentNullException">Thrown when member or typeNameConverters is null</exception> private string GetTsTypeNameForMember(MemberInfo memberInfo, TypeNameConverterCollection typeNameConverters) { // special case - dynamic property/field if (memberInfo.GetCustomAttribute <DynamicAttribute>() != null) { return("any"); } // otherwise, resolve by type Type type = GetMemberType(memberInfo); return(GetTsTypeName(type, typeNameConverters)); }
/// <summary> /// Gets the text for the "extends" section /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> public string GetExtendsText(Type type, TypeNameConverterCollection typeNameConverters) { Requires.NotNull(type, nameof(type)); Requires.NotNull(typeNameConverters, nameof(typeNameConverters)); Type baseType = _typeService.GetBaseType(type); if (baseType == null) { return(""); } string baseTypeName = _typeService.GetTsTypeName(baseType, typeNameConverters, true); return(_templateService.GetExtendsText(baseTypeName)); }
/// <summary> /// Gets TypeScript type name for a dictionary type /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> private string GetTsDictionaryTypeName(Type type, TypeNameConverterCollection typeNameConverters) { Type interfaceType = type.GetInterface("System.Collections.Generic.IDictionary`2") ?? type; Type keyType = interfaceType.GetGenericArguments()[0]; Type valueType = interfaceType.GetGenericArguments()[1]; string keyTypeName = GetTsTypeName(keyType, typeNameConverters); string valueTypeName = GetTsTypeName(valueType, typeNameConverters); if (!keyTypeName.In("number", "string")) { throw new CoreException($"Error when determining TypeScript type for C# type '{type.FullName}':" + " TypeScript dictionary key type must be either 'number' or 'string'"); } return($"{{ [key: {keyTypeName}]: {valueTypeName}; }}"); }
/// <summary> /// Gets the text for the "extends" section /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> public string GetExtendsText(Type type, TypeNameConverterCollection typeNameConverters) { var extendsText = ""; Type baseType = _typeService.GetBaseType(type); if (baseType == null) { return(extendsText); } string baseTypeName = _typeService.GetTsTypeName(baseType, typeNameConverters); extendsText = $" extends {baseTypeName}"; return(extendsText); }
public void GetImportsText_TypeGiven_ImportsTextGenerated(Type type, string outputDir, TypeNameConverterCollection fileNameConverters, TypeNameConverterCollection typeNameConverters, IEnumerable <object> typeDependencies, IEnumerable <MemberInfo> tsExportableMembers, string expectedOutput) { _typeDependencyService.GetTypeDependencies(Arg.Any <Type>()).Returns(typeDependencies); _typeService.GetTsExportableMembers(Arg.Any <Type>()).Returns(tsExportableMembers); _templateService.FillImportTemplate(Arg.Any <string>(), Arg.Any <string>(), Arg.Any <string>()).Returns(i => $"{i.ArgAt<string>(0)} | {i.ArgAt<string>(1)} | {i.ArgAt<string>(2)};"); var tsContentGenerator = new TsContentGenerator(_typeDependencyService, _typeService, _templateService, _tsContentParser, _metadataReader); string actualOutput = tsContentGenerator.GetImportsText(type, outputDir, fileNameConverters, typeNameConverters); Assert.Equal(expectedOutput, actualOutput); }
/// <summary> /// Gets the TypeScript type name to generate for a member /// </summary> /// <param name="memberInfo"></param> /// <param name="typeNameConverters"></param> /// <param name="strictNullChecks"></param> /// <param name="csNullableTranslation"></param> /// <returns></returns> public string GetTsTypeNameForMember(MemberInfo memberInfo, TypeNameConverterCollection typeNameConverters, bool strictNullChecks, StrictNullFlags csNullableTranslation) { string typeUnionSuffix = strictNullChecks ? GetStrictNullChecksTypeSuffix(memberInfo, csNullableTranslation) : ""; var typeAttribute = memberInfo.GetCustomAttribute <TsTypeAttribute>(); if (typeAttribute != null) { if (typeAttribute.TypeName.IsNullOrWhitespace()) { throw new CoreException($"No type specified in TsType attribute for member '{memberInfo.Name}' declared in '{memberInfo.DeclaringType?.FullName}'"); } return(typeAttribute.TypeName + typeUnionSuffix); } return(GetTsTypeName(memberInfo, typeNameConverters, isMember: true) + typeUnionSuffix); }
/// <summary> /// Gets code for the 'imports' section for a given type /// </summary> /// <param name="type"></param> /// <param name="outputDir">ExportTs... attribute's output dir</param> /// <param name="fileNameConverters"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> /// <exception cref="ArgumentNullException">Thrown when one of: type, fileNameConverters or typeNameConverters is null</exception> public string GetImportsText(Type type, string outputDir, TypeNameConverterCollection fileNameConverters, TypeNameConverterCollection typeNameConverters) { Requires.NotNull(type, nameof(type)); Requires.NotNull(fileNameConverters, nameof(fileNameConverters)); Requires.NotNull(typeNameConverters, nameof(typeNameConverters)); string result = GetTypeDependencyImportsText(type, outputDir, fileNameConverters, typeNameConverters); result += GetCustomImportsText(type); if (!string.IsNullOrEmpty(result)) { result += "\r\n"; } return(result); }
public void GetTsTypeName_TypeGiven_TsTypeNameReturned(Type type, TypeNameConverterCollection converters, bool forTypeDeclaration, string expectedResult) { //arrange var generatorOptionsProvider = new GeneratorOptionsProvider { GeneratorOptions = new GeneratorOptions { TypeNameConverters = converters } }; _typeService = new TypeService(_metadataReaderFactory, generatorOptionsProvider); //act string actualResult = _typeService.GetTsTypeName(type, forTypeDeclaration); //assert Assert.Equal(expectedResult, actualResult); }
/// <summary> /// Gets TypeScript type name for a type /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <param name="isMember"></param> /// <returns></returns> /// <exception cref="ArgumentNullException">Thrown when type or typeNameConverters is null</exception> /// <exception cref="CoreException">Thrown when collection element type for the passed type is null (occurs only if the passed type is a collection type)</exception> public string GetTsTypeName(Type type, TypeNameConverterCollection typeNameConverters, bool isMember = false) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (typeNameConverters == null) { throw new ArgumentNullException(nameof(typeNameConverters)); } type = GetUnderlyingType(type); // handle simple types if (IsTsSimpleType(type)) { return(GetTsSimpleTypeName(type)); } // handle collection types if (IsCollectionType(type)) { return(GetTsCollectionTypeName(type, typeNameConverters)); } // handle dictionaries if (IsDictionaryType(type)) { return(GetTsDictionaryTypeName(type, typeNameConverters)); } // handle custom generic types if (IsCustomGenericType(type)) { return(GetGenericTsTypeName(type, typeNameConverters, isMember)); } // handle custom types & generic parameters string typeNameNoArity = type.Name.RemoveTypeArity(); return(type.IsGenericParameter ? typeNameNoArity : typeNameConverters.Convert(typeNameNoArity, type)); }
/// <inheritdoc /> public string GetTsTypeName(MemberInfo memberInfo, TypeNameConverterCollection typeNameConverters, bool strictNullChecks, StrictNullFlags csNullableTranslation) { Requires.NotNull(memberInfo, nameof(memberInfo)); Requires.NotNull(typeNameConverters, nameof(typeNameConverters)); string typeUnionSuffix = strictNullChecks ? GetStrictNullChecksTypeSuffix(memberInfo, csNullableTranslation) : ""; var typeAttribute = _metadataReader.GetAttribute <TsTypeAttribute>(memberInfo); if (typeAttribute != null) { if (string.IsNullOrWhiteSpace(typeAttribute.TypeName)) { throw new CoreException($"No type specified in TsType attribute for member '{memberInfo.Name}' declared in '{memberInfo.DeclaringType?.FullName}'"); } return(typeAttribute.TypeName + typeUnionSuffix); } return(GetTsTypeNameForMember(memberInfo, typeNameConverters) + typeUnionSuffix); }
/// <summary> /// Gets TypeScript type name for a member /// </summary> /// <param name="memberInfo"></param> /// <param name="typeNameConverters"></param> /// <param name="isMember"></param> /// <returns></returns> /// <exception cref="ArgumentNullException">Thrown when member or typeNameConverters is null</exception> public string GetTsTypeName(MemberInfo memberInfo, TypeNameConverterCollection typeNameConverters, bool isMember = false) { if (memberInfo == null) { throw new ArgumentNullException(nameof(memberInfo)); } // special case - dynamic property/field if (memberInfo.GetCustomAttribute <DynamicAttribute>() != null) { return("any"); } // otherwise, resolve by type Type type = GetMemberType(memberInfo); return(GetTsTypeName(type, typeNameConverters, isMember)); }
/// <summary> /// Returns TypeScript imports source code related to type dependencies /// </summary> /// <param name="type"></param> /// <param name="outputDir"></param> /// <param name="fileNameConverters"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> private string GetTypeDependencyImportsText(Type type, string outputDir, TypeNameConverterCollection fileNameConverters, TypeNameConverterCollection typeNameConverters) { if (!string.IsNullOrEmpty(outputDir) && !outputDir.EndsWith("/") && !outputDir.EndsWith("\\")) { outputDir += "\\"; } var result = ""; IEnumerable <TypeDependencyInfo> typeDependencies = _typeDependencyService.GetTypeDependencies(type); // exclude base type dependency if TsCustomBaseAttribute is specified (it will be added in custom imports) if (_metadataReader.GetAttribute <TsCustomBaseAttribute>(type) != null) { typeDependencies = typeDependencies.Where(td => !td.IsBase); } foreach (TypeDependencyInfo typeDependencyInfo in typeDependencies) { Type typeDependency = typeDependencyInfo.Type; string dependencyOutputDir = GetTypeDependencyOutputDir(typeDependencyInfo, outputDir); // get path diff string pathDiff = FileSystemUtils.GetPathDiff(outputDir, dependencyOutputDir); pathDiff = pathDiff.StartsWith("..\\") || pathDiff.StartsWith("../") ? pathDiff : $"./{pathDiff}"; // get type & file name string typeDependencyName = typeDependency.Name.RemoveTypeArity(); string fileName = fileNameConverters.Convert(typeDependencyName, typeDependency); // get file path string dependencyPath = Path.Combine(pathDiff, fileName); dependencyPath = dependencyPath.Replace('\\', '/'); string typeName = typeNameConverters.Convert(typeDependencyName, typeDependency); result += _templateService.FillImportTemplate(typeName, "", dependencyPath); } return(result); }
/// <inheritdoc /> public string GetTsTypeName(Type type, TypeNameConverterCollection typeNameConverters, bool forTypeDeclaration = false) { Requires.NotNull(type, nameof(type)); Requires.NotNull(typeNameConverters, nameof(typeNameConverters)); type = StripNullable(type); // handle simple types if (IsTsSimpleType(type)) { return(GetTsSimpleTypeName(type)); } // handle collection types if (IsCollectionType(type)) { return(GetTsCollectionTypeName(type, typeNameConverters)); } // handle dictionaries if (IsDictionaryType(type)) { return(GetTsDictionaryTypeName(type, typeNameConverters)); } // handle custom generic types if (IsCustomGenericType(type)) { return(GetGenericTsTypeName(type, typeNameConverters, forTypeDeclaration)); } // handle custom types & generic parameters string typeNameNoArity = type.Name.RemoveTypeArity(); return(type.IsGenericParameter ? typeNameNoArity : typeNameConverters.Convert(typeNameNoArity, type)); }
public void GetTsTypeName_MemberGiven_TsTypeNameReturned(MemberInfo memberInfo, TypeNameConverterCollection converters, StrictNullTypeUnionFlags csNullableTranslation, string expectedResult) { //arrange var generatorOptionsProvider = new GeneratorOptionsProvider { GeneratorOptions = new GeneratorOptions { TypeNameConverters = converters, CsNullableTranslation = csNullableTranslation } }; _typeService = new TypeService(_metadataReaderFactory, generatorOptionsProvider); //act string actualResult = _typeService.GetTsTypeName(memberInfo); //assert Assert.Equal(expectedResult, actualResult); }
/// <summary> /// Gets TypeScript type name for a generic type - used NOT in type declarations /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> private string GetGenericTsTypeNameForNonDeclaration(Type type, TypeNameConverterCollection typeNameConverters) { return(GetGenericTsTypeNameDeclarationAgnostic(type, typeNameConverters, t => t.IsGenericParameter ? t.Name : GetTsTypeName(t, typeNameConverters))); }
public void GetTsTypeName_TypeGiven_TsTypeNameReturned(Type type, TypeNameConverterCollection converters, bool forTypeDeclaration, string expectedResult) { string actualResult = _typeService.GetTsTypeName(type, converters, forTypeDeclaration); Assert.Equal(expectedResult, actualResult); }
/// <summary> /// Gets TypeScript type name for a collection type /// </summary> /// <param name="type"></param> /// <param name="typeNameConverters"></param> /// <returns></returns> private string GetTsCollectionTypeName(Type type, TypeNameConverterCollection typeNameConverters) { Type elementType = GetTsCollectionElementType(type); return(GetTsTypeName(elementType, typeNameConverters) + "[]"); }
public void GetTsTypeName_MemberGiven_TsTypeNameReturned(MemberInfo memberInfo, TypeNameConverterCollection converters, bool strictNullChecks, StrictNullFlags csNullableTranslation, string expectedResult) { string actualResult = _typeService.GetTsTypeName(memberInfo, converters, strictNullChecks, csNullableTranslation); Assert.Equal(expectedResult, actualResult); }
public void GetTsTypeName_CustomTypeGiven_CustomTsTypeNameReturned(Type type, TypeNameConverterCollection converters, bool forTypeDeclaration, Type customMappingKey, string customMappingValue, string expectedResult) { //arrange var generatorOptionsProvider = new GeneratorOptionsProvider { GeneratorOptions = new GeneratorOptions { CustomTypeMappings = { { customMappingKey.FullName, customMappingValue } }, TypeNameConverters = converters } }; _typeService = new TypeService(_metadataReaderFactory, generatorOptionsProvider); //act string actualResult = _typeService.GetTsTypeName(type, forTypeDeclaration); //assert Assert.Equal(expectedResult, actualResult); }