internal static DefinitionMapData GetDefinitionMapData(ProjectItem projectItem) { // Initialize our result DefinitionMapData result = null; // Try to find our map data for the typescript definition file ProjectItem definitionMapProjectItem = projectItem.ProjectItems .Cast <ProjectItem>() .Where(pi => pi.Name == GenerationService.GenerateFileName(projectItem.Name) + ".map") .FirstOrDefault(); // Continue if found if (definitionMapProjectItem != null) { // Get the text of our mapping file string documentText = VSHelpers.GetDocumentText(definitionMapProjectItem); // Continue if the document has text if (string.IsNullOrWhiteSpace(documentText) == false) { // Try to parse the containing json string // When a SerializationException is getting thrown the document text wasn't valid try { result = JsonConvert.DeserializeObject <DefinitionMapData>(documentText); } catch (JsonSerializationException) { } } } return(result); }
public static string ConvertToTypeScript(ProjectItem sourceItem) { try { Options.ReadOptionOverrides(sourceItem); VSHelpers.WriteOnOutputWindow(string.Format("{0} - Started", sourceItem.Name)); var list = IntellisenseParser.ProcessFile(sourceItem); // path is needed for relative paths of imports var sourceItemPath = sourceItem.Properties.Item("FullPath").Value as string; VSHelpers.WriteOnOutputWindow(string.Format("{0} - Completed", sourceItem.Name)); return(IntellisenseWriter.WriteTypeScript(list.ToList(), sourceItemPath)); } catch (Exception ex) { VSHelpers.WriteOnOutputWindow(string.Format("{0} - Failure", sourceItem.Name)); if (ex is ExceptionForUser) { // "expected" exception, show to user instead of reporting VSHelpers.WriteOnOutputWindow(ex.Message); } else { Telemetry.TrackException("ParseFailure", ex); } return(null); } }
private static IntellisenseType GetType(CodeClass rootElement, CodeTypeRef codeTypeRef, HashSet <string> traversedTypes, HashSet <string> references) { var isArray = codeTypeRef.TypeKind == vsCMTypeRef.vsCMTypeRefArray; var isCollection = codeTypeRef.AsString.StartsWith("System.Collections", StringComparison.Ordinal); var isDictionary = false; var effectiveTypeRef = codeTypeRef; if (isArray && codeTypeRef.ElementType != null) { effectiveTypeRef = effectiveTypeRef.ElementType; } else if (isCollection) { effectiveTypeRef = TryToGuessGenericArgument(rootElement, effectiveTypeRef); } if (isCollection) { isDictionary = codeTypeRef.AsString.StartsWith("System.Collections.Generic.Dictionary", StringComparison.Ordinal) || codeTypeRef.AsString.StartsWith("System.Collections.Generic.IDictionary", StringComparison.Ordinal); } string typeName = effectiveTypeRef.AsFullName; try { var codeClass = effectiveTypeRef.CodeType as CodeClass2; var codeEnum = effectiveTypeRef.CodeType as CodeEnum; var isPrimitive = IsPrimitive(effectiveTypeRef); var result = new IntellisenseType { IsArray = !isDictionary && (isArray || isCollection), IsDictionary = isDictionary, CodeName = effectiveTypeRef.AsString, ClientSideReferenceName = effectiveTypeRef.TypeKind == vsCMTypeRef.vsCMTypeRefCodeType && effectiveTypeRef.CodeType.InfoLocation == vsCMInfoLocation.vsCMInfoLocationProject ? (codeClass != null && HasIntellisense(codeClass.ProjectItem, references) ? (GetNamespace(codeClass) + "." + Utility.CamelCaseClassName(GetClassName(codeClass))) : null) ?? (codeEnum != null && HasIntellisense(codeEnum.ProjectItem, references) ? (GetNamespace(codeEnum) + "." + Utility.CamelCaseClassName(codeEnum.Name)) : null) : null }; if (!isPrimitive && codeClass != null && !traversedTypes.Contains(effectiveTypeRef.CodeType.FullName) && !isCollection) { traversedTypes.Add(effectiveTypeRef.CodeType.FullName); result.Shape = GetProperties(effectiveTypeRef.CodeType.Members, traversedTypes, references).ToList(); traversedTypes.Remove(effectiveTypeRef.CodeType.FullName); } return(result); } catch (InvalidCastException) { VSHelpers.WriteOnOutputWindow(string.Format("ERROR - Cannot find definition for {0}", typeName)); throw new ArgumentException(string.Format("Cannot find definition of {0}", typeName)); } }
public static string ConvertToTypeScriptEnumsOnly(ProjectItem sourceItem, ref DefinitionMapData definitionMapData, out bool isEmpty) { try { // Initialize the definition data if there was no specified if (definitionMapData == null) { definitionMapData = new DefinitionMapData(); } Options.ReadOptionOverrides(sourceItem); VSHelpers.WriteOnOutputWindow(string.Format("{0} - Started (enums only)", sourceItem.Name)); var list = IntellisenseParser.ProcessFile(sourceItem, definitionMapData); VSHelpers.WriteOnOutputWindow(string.Format("{0} - Completed", sourceItem.Name)); return(IntellisenseWriter.WriteTypeScriptEnumsOnly(list, sourceItem, out isEmpty)); } catch (Exception ex) { isEmpty = true; VSHelpers.WriteOnOutputWindow(string.Format("{0} - Failure", sourceItem.Name)); Telemetry.TrackException("ParseFailure", ex); return(null); } }
public static void CreateDtsMapFile(ProjectItem sourceItem, DefinitionMapData definitionMapData) { string sourceFile = sourceItem.FileNames[1]; string dtsFile = GenerationService.GenerateFileName(sourceFile) + ".map"; VSHelpers.CheckFileOutOfSourceControl(dtsFile); File.WriteAllText(dtsFile, JsonConvert.SerializeObject(definitionMapData, Formatting.Indented)); if (sourceItem.ContainingProject.IsKind(ProjectTypes.DOTNET_Core, ProjectTypes.ASPNET_5)) { Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { var dtsItem = VSHelpers.GetProjectItem(dtsFile); if (dtsItem != null) { dtsItem.Properties.Item("DependentUpon").Value = sourceItem.Name; } Telemetry.TrackOperation("FileGenerated"); }), DispatcherPriority.ApplicationIdle, null); } else if (sourceItem.ContainingProject.IsKind(ProjectTypes.WEBSITE_PROJECT)) { sourceItem.ContainingProject.ProjectItems.AddFromFile(dtsFile); } else { sourceItem.ProjectItems.AddFromFile(dtsFile); } }
public static void CopyDtsFile(DefinitionMapData definitionMapData, ProjectItem projectItem, string dts, bool isEnumDefinition) { // There might be paths where this file should be copied to foreach (string copyPath in definitionMapData.CopyPaths) { // Ignore empty paths if (string.IsNullOrWhiteSpace(copyPath)) { continue; } // Get the path from our project item and combine it with the target path and target name string filePath = Path.GetFullPath(Path.Combine( Path.GetDirectoryName(projectItem.FileNames[1]), copyPath, GenerationService.GetCopyDtsFileName(definitionMapData, projectItem, isEnumDefinition))); // Try to write our definition file to the new path too try { File.WriteAllText(filePath, dts); VSHelpers.WriteOnOutputWindow($"File written to \"{filePath}\""); } catch (Exception ex) { VSHelpers.WriteOnOutputWindow($"Could not write file to \"{filePath}\"{Environment.NewLine}" + $"Reason: {ex.Message}"); } } }
private static List <string> GetReferences(IEnumerable <IntellisenseObject> objects, ProjectItem sourceItem) { if (Options.KeepReferencesUnchanged) { ProjectItem generatedProjectItem = sourceItem.ProjectItems .Cast <ProjectItem>() .Where(item => GenerationService.GenerateFileName(sourceItem.Name) == item.Name) .FirstOrDefault(); if (generatedProjectItem != null) { string documentText = VSHelpers.GetDocumentText(generatedProjectItem); if (string.IsNullOrWhiteSpace(documentText) == false) { string pattern = "/// <reference path=\"(.*)\" />\r\n"; return(new Regex(pattern).Matches(documentText) .Cast <Match>() .Select(m => m.Groups[1].Value) .OrderBy(r => r) .ToList()); } } } return(objects .SelectMany(o => o.References) .Where(r => Path.GetFileName(r) != GenerationService.GenerateFileName(sourceItem.Name)) .Distinct() .OrderBy(r => r) .ToList()); }
public static void CreateDtsFile(ProjectItem sourceItem) { string sourceFile = sourceItem.FileNames[1]; string dtsFile = Utility.GenerateFileName(sourceFile); string dts = ConvertToTypeScript(sourceItem); VSHelpers.CheckFileOutOfSourceControl(dtsFile); File.WriteAllText(dtsFile, dts); if (sourceItem.ContainingProject.IsKind(ProjectTypes.DOTNET_Core, ProjectTypes.ASPNET_5)) { Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { var dtsItem = VSHelpers.GetProjectItem(dtsFile); if (dtsItem != null) { dtsItem.Properties.Item("DependentUpon").Value = sourceItem.Name; } Telemetry.TrackOperation("FileGenerated"); }), DispatcherPriority.ApplicationIdle, null); } else if (sourceItem.ContainingProject.IsKind(ProjectTypes.WEBSITE_PROJECT)) { sourceItem.ContainingProject.ProjectItems.AddFromFile(dtsFile); } }
public static void CreateDtsFile(ProjectItem sourceItem) { string sourceFile = sourceItem.FileNames[1]; string dtsFile = GenerationService.GenerateFileName(sourceFile); string dtsEnumFile = GenerationService.GenerateFileName(sourceFile); // Get metadata from our project item DefinitionMapData definitionMapData = VSHelpers.GetDefinitionMapData(sourceItem); string dts = ConvertToTypeScriptWithoutEnums(sourceItem, ref definitionMapData, out bool isEmpty); string dtsEnumOnly = ConvertToTypeScriptEnumsOnly(sourceItem, ref definitionMapData, out bool isEmptyEnum); VSHelpers.CheckFileOutOfSourceControl(dtsFile); File.WriteAllText(dtsFile, dts); if (isEmptyEnum == false) { File.WriteAllText(dtsEnumFile, dtsEnumOnly); } if (sourceItem.ContainingProject.IsKind(ProjectTypes.DOTNET_Core, ProjectTypes.ASPNET_5)) { Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { var dtsItem = VSHelpers.GetProjectItem(dtsFile); if (dtsItem != null) { dtsItem.Properties.Item("DependentUpon").Value = sourceItem.Name; } if (isEmptyEnum == false) { var dtsItem2 = VSHelpers.GetProjectItem(dtsEnumFile); if (dtsItem2 != null) { dtsItem2.Properties.Item("DependentUpon").Value = sourceItem.Name; } } Telemetry.TrackOperation("FileGenerated"); }), DispatcherPriority.ApplicationIdle, null); } else if (sourceItem.ContainingProject.IsKind(ProjectTypes.WEBSITE_PROJECT)) { sourceItem.ContainingProject.ProjectItems.AddFromFile(dtsFile); if (isEmptyEnum == false) { sourceItem.ContainingProject.ProjectItems.AddFromFile(dtsEnumFile); } } // Also create the definition map data and add it to our project item CreateDtsMapFile(sourceItem, definitionMapData); }
public static void ReadOptionOverrides(ProjectItem sourceItem, bool display = true) { Project proj = sourceItem.ContainingProject; string jsonName = ""; foreach (ProjectItem item in proj.ProjectItems) { if (item.Name.ToLower() == OVERRIDE_FILE_NAME.ToLower()) { jsonName = item.FileNames[0]; break; } } if (!string.IsNullOrEmpty(jsonName)) { // it has been modified since last read - so read again try { overrides = JsonConvert.DeserializeObject <OptionsOverride>(File.ReadAllText(jsonName)); if (display) { VSHelpers.WriteOnOutputWindow(string.Format("Override file processed: {0}", jsonName)); } else { System.Diagnostics.Debug.WriteLine(string.Format("Override file processed: {0}", jsonName)); } } catch (Exception e) when(e is Newtonsoft.Json.JsonReaderException || e is Newtonsoft.Json.JsonSerializationException) { overrides = null; // incase the read fails VSHelpers.WriteOnOutputWindow(string.Format("Error in Override file: {0}", jsonName)); VSHelpers.WriteOnOutputWindow(e.Message); throw; } } else { if (display) { VSHelpers.WriteOnOutputWindow("Using Global Settings"); } else { System.Diagnostics.Debug.WriteLine("Using Global Settings"); } overrides = null; } }
private void FileActionOccurred(object sender, TextDocumentFileActionEventArgs e) { if (e.FileActionType != FileActionTypes.ContentSavedToDisk) { return; } _item = VSHelpers.GetProjectItem(e.FilePath); Options.ReadOptionOverrides(_item, false); string fileName = Utility.GenerateFileName(e.FilePath); if (File.Exists(fileName)) { DtsPackage.EnsurePackageLoad(); CreateDtsFile(_item); } }
public static string ConvertToTypeScript(ProjectItem sourceItem) { try { Options.ReadOptionOverrides(sourceItem); VSHelpers.WriteOnOutputWindow(string.Format("{0} - Started", sourceItem.Name)); var list = IntellisenseParser.ProcessFile(sourceItem); VSHelpers.WriteOnOutputWindow(string.Format("{0} - Completed", sourceItem.Name)); return(IntellisenseWriter.WriteTypeScript(list)); } catch (Exception ex) { VSHelpers.WriteOnOutputWindow(string.Format("{0} - Failure", sourceItem.Name)); Telemetry.TrackException("ParseFailure", ex); return(null); } }
public void TextViewCreated(IWpfTextView textView) { if (!_documentService.TryGetTextDocument(textView.TextBuffer, out var doc)) { return; } _item = VSHelpers.GetProjectItem(doc.FilePath); if (_item?.ContainingProject == null || !_item.ContainingProject.IsKind(ProjectTypes.DOTNET_Core, ProjectTypes.ASPNET_5, ProjectTypes.WEBSITE_PROJECT)) { return; } doc.FileActionOccurred += FileActionOccurred; }
private static void WriteTypescriptToFile(string contents, string typescriptFilename, ProjectItem sourceItem) { if (!string.IsNullOrEmpty(contents)) { VSHelpers.CheckFileOutOfSourceControl(typescriptFilename); File.WriteAllText(typescriptFilename, contents); VSHelpers.WriteOnOutputWindow($"Written: {typescriptFilename}"); } else { try { File.Delete(typescriptFilename); VSHelpers.WriteOnOutputWindow($"Deleted (no content): {typescriptFilename}"); } catch { } } if (sourceItem.ContainingProject.IsKind(ProjectTypes.DOTNET_Core, ProjectTypes.ASPNET_5)) { Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { var dtsItem = VSHelpers.GetProjectItem(typescriptFilename); if (!string.IsNullOrEmpty(contents)) { if (dtsItem != null) { dtsItem.Properties.Item("DependentUpon").Value = sourceItem.Name; } Telemetry.TrackOperation("FileGenerated"); } else { dtsItem.Delete(); Telemetry.TrackOperation("FileDeleted"); } }), DispatcherPriority.ApplicationIdle, null); } else if (sourceItem.ContainingProject.IsKind(ProjectTypes.WEBSITE_PROJECT) && !string.IsNullOrEmpty(contents)) { sourceItem.ContainingProject.ProjectItems.AddFromFile(typescriptFilename); } }
protected override byte[] GenerateCode(string inputFileName, string inputFileContent) { ProjectItem item = Dte.Solution.FindProjectItem(inputFileName); OriginalExt = Path.GetExtension(inputFileName); if (item != null) { try { Telemetry.TrackOperation("FileGenerated"); string output = GenerationService.ConvertToTypeScript(item); if (!string.IsNullOrWhiteSpace(Options.NodeModulePath)) { // generate a Node module instead of a d.ts file. string outputFile = Path.ChangeExtension(inputFileName, ".ts"); string projectPath = Path.GetDirectoryName(item.ContainingProject.FileName); outputFile = outputFile.Substring(projectPath.Length + 1); // strip the initial part of the path outputFile = Path.Combine(projectPath, Options.NodeModulePath, outputFile); var di = Directory.CreateDirectory(Path.GetDirectoryName(outputFile)); if (di != null && di.Exists) { VSHelpers.CheckFileOutOfSourceControl(outputFile); File.WriteAllText(outputFile, output); output = $"// Node module file generated at {MakeRelativePath(InputFilePath, outputFile)}"; } } return(Encoding.UTF8.GetBytes(output)); } catch (Exception ex) { VSHelpers.WriteOnOutputWindow(string.Format("{0} - File Generation Failure", inputFileName)); VSHelpers.WriteOnOutputWindow(ex.StackTrace); Telemetry.TrackOperation("FileGenerated", Microsoft.VisualStudio.Telemetry.TelemetryResult.Failure); Telemetry.TrackException("FileGenerated", ex); } } return(new byte[0]); }
protected override byte[] GenerateCode(string inputFileName, string inputFileContent) { ProjectItem item = Dte.Solution.FindProjectItem(inputFileName); this.originalExt = Path.GetExtension(inputFileName); if (item != null) { try { // Get metadata from our project item DefinitionMapData definitionMapData = VSHelpers.GetDefinitionMapData(item); string dts = GenerationService.ConvertToTypeScriptWithoutEnums(item, ref definitionMapData, out bool isEmpty); string dtsEnum = GenerationService.ConvertToTypeScriptEnumsOnly(item, ref definitionMapData, out bool isEmptyEnum); Telemetry.TrackOperation("FileGenerated"); if (isEmpty == false) { // Copy our dts file to the specified paths in the definition map data GenerationService.CopyDtsFile(definitionMapData, item, dts, false); } if (isEmptyEnum == false) { GenerationService.CopyDtsFile(definitionMapData, item, dtsEnum, true); GenerationService.CreateEnumFile(item, dtsEnum); } // And in the last step write the map file which contains some metadata GenerationService.CreateDtsMapFile(item, definitionMapData); return(Encoding.UTF8.GetBytes(dts)); } catch (Exception ex) { Telemetry.TrackOperation("FileGenerated", Microsoft.VisualStudio.Telemetry.TelemetryResult.Failure); Telemetry.TrackException("FileGenerated", ex); } } return(new byte[0]); }
private void Execute(object sender, EventArgs e) { if (_item == null) { return; } Options.ReadOptionOverrides(_item, false); // .NET Core and Website projects if (_item.ContainingProject.IsKind(ProjectTypes.DOTNET_Core, ProjectTypes.ASPNET_5, ProjectTypes.WEBSITE_PROJECT)) { string dtsFile = GenerationService.GenerateFileName(_item.FileNames[1]); bool synOn = File.Exists(dtsFile); if (synOn) { var dtsItem = VSHelpers.GetProjectItem(dtsFile); dtsItem?.Delete(); File.Delete(dtsFile); } else { GenerationService.CreateDtsFile(_item); } } // Legacy .NET projects else { bool synOn = _item.Properties.Item("CustomTool").Value.ToString() == DtsGenerator.Name; if (synOn) { _item.Properties.Item("CustomTool").Value = ""; Telemetry.TrackUserTask("EnableGeneration"); } else { _item.Properties.Item("CustomTool").Value = DtsGenerator.Name; Telemetry.TrackUserTask("DisabledGeneration"); } } }
public static void CreateEnumFile(ProjectItem sourceItem, string content) { string sourceFile = sourceItem.FileNames[1]; string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(sourceFile); while (fileNameWithoutExtension.Contains(".")) { fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileNameWithoutExtension); } string dtsFile = Path.Combine(Path.GetDirectoryName(sourceFile), fileNameWithoutExtension += "Enum.ts"); VSHelpers.CheckFileOutOfSourceControl(dtsFile); File.WriteAllText(dtsFile, content); if (sourceItem.ContainingProject.IsKind(ProjectTypes.DOTNET_Core, ProjectTypes.ASPNET_5)) { Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { var dtsItem = VSHelpers.GetProjectItem(dtsFile); if (dtsItem != null) { dtsItem.Properties.Item("DependentUpon").Value = sourceItem.Name; } Telemetry.TrackOperation("FileGenerated"); }), DispatcherPriority.ApplicationIdle, null); } else if (sourceItem.ContainingProject.IsKind(ProjectTypes.WEBSITE_PROJECT)) { sourceItem.ContainingProject.ProjectItems.AddFromFile(dtsFile); } else { sourceItem.ProjectItems.AddFromFile(dtsFile); } }
public static string WriteTypeScriptWithoutEnums(IEnumerable <IntellisenseObject> objects, ProjectItem sourceItem, out bool isEmpty) { isEmpty = true; var sb = new StringBuilder(); foreach (var ns in objects.GroupBy(o => o.Namespace)) { List <string> references = GetReferences(objects, sourceItem); if (references.Count > 0) { foreach (string referencePath in references.OrderBy(p => Path.GetFileName(p))) { string path = Path.GetFileName(referencePath); ProjectItem definitionMapProjectItem = sourceItem.DTE.Solution.FindProjectItem(referencePath); if (definitionMapProjectItem != null) { DefinitionMapData definitionMapData = VSHelpers.GetDefinitionMapData(definitionMapProjectItem.Collection.Parent as ProjectItem); if (definitionMapData != null) { if (string.IsNullOrWhiteSpace(definitionMapData.CustomName) == false) { path = GenerationService.GetCopyDtsFileName(definitionMapData, definitionMapProjectItem, false); } } } sb.AppendFormat("/// <reference path=\"{0}\" />\r\n", path); } sb.AppendLine(); } if (!Options.GlobalScope) { sb.AppendFormat("declare module {0} {{\r\n", ns.Key); } foreach (IntellisenseObject io in ns) { if (io.IsEnum) { continue; } isEmpty = false; if (!string.IsNullOrEmpty(io.Summary)) { sb.AppendLine("\t/** " + _whitespaceTrimmer.Replace(io.Summary, "") + " */"); } string type = Options.ClassInsteadOfInterface ? "\tclass " : "\tinterface "; sb.Append(type).Append(Utility.CamelCaseClassName(io.Name)).Append(" "); if (!string.IsNullOrEmpty(io.BaseName)) { sb.Append("extends "); if (Options.GlobalScope == false) { sb.Append(ns.Key).Append("."); } if (!string.IsNullOrEmpty(io.BaseNamespace) && io.BaseNamespace != io.Namespace) { sb.Append(io.BaseNamespace).Append("."); } sb.Append(Utility.CamelCaseClassName(io.BaseName)).Append(" "); } WriteTSInterfaceDefinition(sb, "\t", io.Properties); sb.AppendLine(); } if (!Options.GlobalScope) { sb.AppendLine("}"); } } return(sb.ToString()); }
public static string WriteTypeScriptEnumsOnly(IEnumerable <IntellisenseObject> objects, ProjectItem sourceItem, out bool isEmpty) { isEmpty = true; var sb = new StringBuilder(); foreach (var ns in objects.GroupBy(o => o.Namespace)) { List <string> references = GetReferences(objects, sourceItem); if (references.Count > 0) { foreach (string referencePath in references.OrderBy(p => Path.GetFileName(p))) { string path = Path.GetFileName(referencePath); ProjectItem definitionMapProjectItem = sourceItem.DTE.Solution.FindProjectItem(referencePath); if (definitionMapProjectItem != null) { DefinitionMapData definitionMapData = VSHelpers.GetDefinitionMapData(definitionMapProjectItem.Collection.Parent as ProjectItem); if (definitionMapData != null) { if (string.IsNullOrWhiteSpace(definitionMapData.CustomName) == false) { path = GenerationService.GetCopyDtsFileName(definitionMapData, definitionMapProjectItem, true); } } } sb.AppendFormat("/// <reference path=\"{0}\" />\r\n", path); } sb.AppendLine(); } if (!Options.GlobalScope) { sb.AppendFormat("declare module {0} {{\r\n", ns.Key); } foreach (IntellisenseObject io in ns) { if (io.IsEnum == false) { continue; } isEmpty = false; if (!string.IsNullOrEmpty(io.Summary)) { sb.AppendLine("\t/** " + _whitespaceTrimmer.Replace(io.Summary, "") + " */"); } sb.AppendLine("\tenum " + Utility.CamelCaseClassName(io.Name) + " {"); foreach (var p in io.Properties) { WriteTypeScriptComment(p, sb); if (p.InitExpression != null) { sb.AppendLine("\t\t" + Utility.CamelCaseEnumValue(p.Name) + " = " + CleanEnumInitValue(p.InitExpression) + ","); } else { sb.AppendLine("\t\t" + Utility.CamelCaseEnumValue(p.Name) + ","); } } sb.AppendLine("\t}"); } if (!Options.GlobalScope) { sb.AppendLine("}"); } } return(sb.ToString()); }
private static IntellisenseType GetType(CodeClass rootElement, CodeTypeRef codeTypeRef, HashSet <string> traversedTypes, HashSet <string> references) { var isArray = codeTypeRef.TypeKind == vsCMTypeRef.vsCMTypeRefArray; var isCollection = codeTypeRef.AsString.StartsWith("System.Collections", StringComparison.Ordinal); var isDictionary = false; var effectiveTypeRef = codeTypeRef; if (isArray && codeTypeRef.ElementType != null) { effectiveTypeRef = effectiveTypeRef.ElementType; } else if (isCollection) { effectiveTypeRef = TryToGuessGenericArgument(rootElement, effectiveTypeRef); } if (isCollection) { isDictionary = codeTypeRef.AsString.StartsWith("System.Collections.Generic.Dictionary", StringComparison.Ordinal) || codeTypeRef.AsString.StartsWith("System.Collections.Generic.IDictionary", StringComparison.Ordinal); } string typeName = effectiveTypeRef.AsFullName; try { //VSHelpers.WriteOnBuildDebugWindow($"%{(effectiveTypeRef.CodeType as CodeInterface2) != null}%"); var codeInterface = effectiveTypeRef.CodeType as CodeInterface2; var codeClass = effectiveTypeRef.CodeType as CodeClass2; var codeEnum = effectiveTypeRef.CodeType as CodeEnum; var isPrimitive = IsPrimitive(effectiveTypeRef); //VSHelpers.WriteOnBuildDebugWindow($"###{effectiveTypeRef.CodeType.GetType().FullName}"); var result = new IntellisenseType { IsArray = !isDictionary && (isArray || isCollection), IsDictionary = isDictionary, CodeName = effectiveTypeRef.AsString }; //VSHelpers.WriteOnBuildDebugWindow($"#{result.CodeName}#{result.TypeScriptName}#{effectiveTypeRef.AsString}#{effectiveTypeRef.AsFullName}#{effectiveTypeRef.CodeType}"); //VSHelpers.WriteOnBuildDebugWindow($"##{effectiveTypeRef.TypeKind}##{vsCMTypeRef.vsCMTypeRefCodeType}##{effectiveTypeRef.CodeType.InfoLocation}##{vsCMInfoLocation.vsCMInfoLocationProject}"); result.ClientSideReferenceName = null; if (effectiveTypeRef.TypeKind == vsCMTypeRef.vsCMTypeRefCodeType) { var hasIntellisense = Options.IgnoreIntellisense; if (effectiveTypeRef.CodeType.InfoLocation == vsCMInfoLocation.vsCMInfoLocationProject) { if (codeClass != null) { hasIntellisense = HasIntellisense(codeClass.ProjectItem, references); } if (codeEnum != null) { hasIntellisense = HasIntellisense(codeEnum.ProjectItem, references); } } //VSHelpers.WriteOnBuildDebugWindow($"@{codeClass != null}@{codeEnum != null}@{hasIntellisense}@{Options.DeclareModule}"); result.ClientSideReferenceName = (codeClass != null && hasIntellisense ? (Options.DeclareModule ? GetNamespace(codeClass) + "." : "") + Utility.CamelCaseClassName(GetClassName(codeClass)) : null) ?? (codeEnum != null && hasIntellisense ? (Options.DeclareModule ? GetNamespace(codeEnum) + "." : "") + Utility.CamelCaseClassName(GetEnumName(codeEnum)) : null) ?? (codeInterface != null && hasIntellisense ? (Options.DeclareModule ? GetNamespace(codeInterface) + "." : "") + Utility.CamelCaseClassName(GetInterfaceName(codeInterface)) : null); } if (!isPrimitive && (codeClass != null || codeEnum != null) && !traversedTypes.Contains(effectiveTypeRef.CodeType.FullName) && !isCollection) { traversedTypes.Add(effectiveTypeRef.CodeType.FullName); result.Shape = GetProperties(effectiveTypeRef.CodeType.Members, traversedTypes, references).ToList(); traversedTypes.Remove(effectiveTypeRef.CodeType.FullName); } return(result); } catch (InvalidCastException) { VSHelpers.WriteOnOutputWindow(string.Format("ERROR - Cannot find definition for {0}", typeName)); throw new ArgumentException(string.Format("Cannot find definition of {0}", typeName)); } }
/// <summary> /// Generates TypeScript file for given C# class/enum (IntellisenseObject). /// </summary> /// <param name="objects">IntellisenseObject of class/enum</param> /// <param name="sourceItemPath">Path to C# source file</param> /// <returns>TypeScript file content as string</returns> public static string WriteTypeScript(IList <IntellisenseObject> objects, string sourceItemPath) { var sb = new StringBuilder(); sb.AppendLine("// ------------------------------------------------------------------------------"); sb.AppendLine("// <auto-generated>"); sb.AppendFormat("// This file was generated by TypeScript Definition Generator v{0}\r\n", Vsix.Version); sb.AppendLine("// </auto-generated>"); sb.AppendLine("// ------------------------------------------------------------------------------"); string export = !Options.DeclareModule ? "export " : string.Empty; string prefixModule = Options.DeclareModule ? "\t" : string.Empty; var sbBody = new StringBuilder(); var neededImports = new List <string>(); foreach (var ns in objects.GroupBy(o => o.Namespace)) { if (Options.DeclareModule) { sbBody.AppendFormat("declare module {0} {{\r\n", ns.Key); } foreach (IntellisenseObject io in ns) { if (!string.IsNullOrEmpty(io.Summary)) { sbBody.Append(prefixModule).AppendLine("/** " + _whitespaceTrimmer.Replace(io.Summary, "") + " */"); } if (io.IsEnum) { string type = "enum "; sbBody.Append(prefixModule).Append(export).Append(type).Append(Utility.CamelCaseClassName(io.Name)).Append(" "); sbBody.AppendLine("{"); WriteTSEnumDefinition(sbBody, prefixModule + "\t", io.Properties); sbBody.Append(prefixModule).AppendLine("}"); } else { string type = Options.ClassInsteadOfInterface ? "class " : "interface "; sbBody.Append(prefixModule).Append(export).Append(type).Append(Utility.CamelCaseClassName(io.Name)).Append(" "); if (!string.IsNullOrEmpty(io.BaseName)) { sbBody.Append("extends "); if (!string.IsNullOrEmpty(io.BaseNamespace) && io.BaseNamespace != io.Namespace) { sbBody.Append(io.BaseNamespace).Append("."); } sbBody.Append(Utility.CamelCaseClassName(io.BaseName)).Append(" "); } sbBody.AppendLine("{"); WriteTSInterfaceDefinition(sbBody, prefixModule + "\t", io.Properties); sbBody.Append(prefixModule).AppendLine("}"); // Remember client-side references for which we need imports. // Dictionary are built-in into TS, they need no imports. neededImports.AddRange(io.Properties.Where(p => p.Type.ClientSideReferenceName != null && !p.Type.IsDictionary).Select(p => p.Type.ClientSideReferenceName)); } } if (Options.DeclareModule) { sbBody.AppendLine("}"); } } // if interface, import external interfaces and base classes if (!Options.DeclareModule) { var imports = new List <string>(); var references = objects.SelectMany(o => o.References).Distinct(); foreach (var reference in references) { var referencePathRelative = Utility.GetRelativePath(sourceItemPath, reference); // remove trailing ".ts" which is not expected for TS imports referencePathRelative = referencePathRelative.Substring(0, referencePathRelative.Length - 3); // make sure path contains forward slashes which are expected by TS referencePathRelative = referencePathRelative.Replace(Path.DirectorySeparatorChar, '/'); var referenceName = Utility.RemoveDefaultExtension(Path.GetFileName(reference)); // skipped indirect references if (!neededImports.Contains(referenceName)) { continue; } sb.AppendLine($"import {{ {referenceName} }} from \"{referencePathRelative}\";"); imports.Add(referenceName); } // also import base classes if not yet imported var baseClasses = objects.Select(o => o.BaseName).Where(b => b != null && !imports.Contains(b)).Distinct(); foreach (var b in baseClasses) { var expectedBaseClassPath = Path.Combine(Path.GetDirectoryName(sourceItemPath), b + ".cs"); if (!File.Exists(expectedBaseClassPath)) { throw new ExceptionForUser($"Could not find base class for {b}. Expected path: {expectedBaseClassPath}"); } sb.AppendLine($"import {{ {b} }} from \"./{b}.generated\";"); imports.Add(b); } var notImportedNeededImports = neededImports.Except(imports).ToList(); if (notImportedNeededImports.Any()) { var exceptionForDeveloper = $"Sorry, needed imports missing: {string.Join(", ", notImportedNeededImports)}. " + $"Make sure file names match contained class/enum name."; sb.AppendLine($"// {exceptionForDeveloper}"); VSHelpers.WriteOnOutputWindow(exceptionForDeveloper); //throw new ExceptionForUser(exceptionForDeveloper); } } sb.Append(sbBody); if (Options.EOLType == EOLType.LF) { sb.Replace("\r\n", "\n"); } if (!Options.IndentTab) { sb.Replace("\t", new string(' ', Options.IndentTabSize)); } return(sb.ToString()); }
/// <summary> /// Generates TypeScript file for given C# class/enum (IntellisenseObject). /// </summary> /// <param name="objects">IntellisenseObject of class/enum</param> /// <param name="sourceItemPath">Path to C# source file</param> /// <returns>TypeScript file content as string</returns> public static string WriteTypeScript(IList <IntellisenseObject> objects, string sourceItemPath) { var sb = new StringBuilder(); if (Options.AddAmdModuleName) { var moduleName = Path.GetFileNameWithoutExtension(sourceItemPath) + Path.GetFileNameWithoutExtension(Utility.GetDefaultExtension(sourceItemPath)); sb.AppendLine($"/// <amd-module name='{moduleName}'/>"); } sb.AppendLine("// ------------------------------------------------------------------------------"); sb.AppendLine("// <auto-generated>"); sb.AppendFormat("// This file was generated by TypeScript Definition Generator v{0}\r\n", Vsix.Version); sb.AppendLine("// </auto-generated>"); sb.AppendLine("// ------------------------------------------------------------------------------"); string export = !Options.DeclareModule ? "export " : string.Empty; string prefixModule = Options.DeclareModule ? "\t" : string.Empty; var sbBody = new StringBuilder(); var neededImports = new List <string>(); var imports = new List <string>(); var exports = new List <string>(); foreach (var ns in objects.GroupBy(o => o.Namespace)) { if (Options.DeclareModule) { sbBody.AppendFormat("declare module {0} {{\r\n", ns.Key); } foreach (IntellisenseObject io in ns) { WriteTypeScriptComment(io.Summary, sbBody, prefixModule); if (io.IsEnum) { string type = "const enum "; sbBody.Append(prefixModule).Append(export).Append(type).Append(Utility.CamelCaseClassName(io.Name)).Append(" "); if (!Options.DeclareModule) { exports.Add(Utility.CamelCaseClassName(io.Name)); } sbBody.AppendLine("{"); WriteTSEnumDefinition(sbBody, prefixModule + "\t", io.Properties); sbBody.Append(prefixModule).AppendLine("}"); } else { string type = Options.ClassInsteadOfInterface ? "class " : "interface "; sbBody.Append(prefixModule).Append(export).Append(type).Append(Utility.CamelCaseClassName(io.Name)).Append(" "); if (!Options.DeclareModule) { exports.Add(Utility.CamelCaseClassName(io.Name)); } string[] summaryLines = io.Summary?.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); string optionsLine = summaryLines?.SingleOrDefault(l => l.StartsWith("TypeScriptDefinitionGenerator:")); var ignoreBase = optionsLine != null && optionsLine.Contains("IgnoreBaseType"); if (!string.IsNullOrEmpty(io.BaseName) && !ignoreBase) { var extendsContent = string.Empty; sbBody.Append("#{ExtendsPlaceholder_" + io.BaseName + "}"); if (!string.IsNullOrEmpty(io.BaseNamespace) && io.BaseNamespace != io.Namespace) { extendsContent = $"extends {io.BaseNamespace}.{Utility.CamelCaseClassName(io.BaseName)} "; } else { extendsContent = $"extends {Utility.CamelCaseClassName(io.BaseName)} "; } if (!ExtendsPlaceholders.ContainsKey(io.BaseName)) { ExtendsPlaceholders.Add(io.BaseName, extendsContent); } } sbBody.AppendLine("{"); WriteTSInterfaceDefinition(sbBody, prefixModule + "\t", io.Properties); sbBody.Append(prefixModule).AppendLine("}"); // Remember client-side references for which we need imports. // Dictionary are built-in into TS, they need no imports. neededImports.AddRange(io.Properties.Where(p => p.Type.ClientSideReferenceName != null && !p.Type.IsDictionary).Select(p => p.Type.ClientSideReferenceName)); // Remember that this class was already included (imported) imports.Add(Utility.CamelCaseClassName(io.Name)); } } if (Options.DeclareModule) { sbBody.AppendLine("}"); } } neededImports.RemoveAll(n => imports.Contains(n)); // if interface, import external interfaces and base classes if (!Options.DeclareModule) { var references = objects.SelectMany(o => o.References).Distinct(); foreach (var reference in references) { var referencePathRelative = Utility.GetRelativePath(sourceItemPath, reference); // remove trailing ".ts" which is not expected for TS imports referencePathRelative = referencePathRelative.Substring(0, referencePathRelative.Length - 3); // make sure path contains forward slashes which are expected by TS referencePathRelative = referencePathRelative.Replace(Path.DirectorySeparatorChar, '/'); var referenceName = Utility.RemoveDefaultExtension(Path.GetFileName(reference)); // skipped indirect references if (!neededImports.Contains(referenceName)) { continue; } sb.AppendLine($"import {{ {referenceName} }} from \"{referencePathRelative}\";"); imports.Add(referenceName); } // also import base classes if not yet imported var baseClasses = objects.Select(o => o.BaseName).Where(b => b != null && !imports.Contains(b)).Distinct(); foreach (var b in baseClasses) { var expectedBaseClassPath = Path.Combine(Path.GetDirectoryName(sourceItemPath), b + ".cs"); if (!File.Exists(expectedBaseClassPath)) { var warningMessage = $"Sorry, ignoring base class '{b}' because expected source file does not exist: {expectedBaseClassPath} "; sb.AppendLine($"// {warningMessage}"); VSHelpers.WriteOnOutputWindow(warningMessage); // remove placeholder from sbBody to prevent "extends " to be inserted later sbBody.Replace("#{ExtendsPlaceholder_" + b + "}", string.Empty); } else { sb.AppendLine($"import {{ {b} }} from \"./{b}.generated\";"); imports.Add(b); } } var notImportedNeededImports = neededImports.Except(imports).Except(exports).ToList(); if (notImportedNeededImports.Any()) { var warningMessage = $"Sorry, needed imports missing: {string.Join(", ", notImportedNeededImports)}. " + $"Make sure file names match contained class/enum name."; sb.AppendLine($"// {warningMessage}"); VSHelpers.WriteOnOutputWindow(warningMessage); } } foreach (var placeholder in ExtendsPlaceholders) { sbBody.Replace("#{ExtendsPlaceholder_" + placeholder.Key + "}", placeholder.Value); } sb.Append(sbBody); if (Options.EOLType == EOLType.LF) { sb.Replace("\r\n", "\n"); } if (!Options.IndentTab) { sb.Replace("\t", new string(' ', Options.IndentTabSize)); } return(sb.ToString()); }
private static IntellisenseType GetType(ProjectItem projectItem, DefinitionMapData definitionMapData, CodeClass rootElement, CodeTypeRef codeTypeRef, HashSet <string> traversedTypes, HashSet <string> references) { var isArray = codeTypeRef.TypeKind == vsCMTypeRef.vsCMTypeRefArray; var isCollection = codeTypeRef.AsString.StartsWith("System.Collections", StringComparison.Ordinal); var isNullable = codeTypeRef.AsFullName.StartsWith("System.Nullable", StringComparison.Ordinal); var isDictionary = false; var effectiveTypeRef = codeTypeRef; if (isArray && codeTypeRef.ElementType != null) { effectiveTypeRef = effectiveTypeRef.ElementType; } else if (isCollection || isNullable) { effectiveTypeRef = TryToGuessGenericArgument(rootElement, effectiveTypeRef); } if (isCollection) { isDictionary = codeTypeRef.AsString.StartsWith("System.Collections.Generic.Dictionary", StringComparison.Ordinal); } string typeName = effectiveTypeRef.AsFullName; try { var codeClass = effectiveTypeRef.CodeType as CodeClass2; var codeEnum = effectiveTypeRef.CodeType as CodeEnum; var isPrimitive = IsPrimitive(effectiveTypeRef); // Some definitions may be defined inside of another project if (Options.AssumeExternalType == false && (codeClass != null || codeEnum != null) && effectiveTypeRef.TypeKind == vsCMTypeRef.vsCMTypeRefCodeType && effectiveTypeRef.CodeType.InfoLocation == vsCMInfoLocation.vsCMInfoLocationExternal) { // Try retrieving the external codeclass by walking all references the current project has if (TryGetExternalType(projectItem, definitionMapData, codeClass != null ? codeClass.FullName : codeEnum.FullName, out CodeClass2 externalCodeClass, out CodeEnum externalCodeEnum)) { // If successful use the new type codeClass = externalCodeClass; codeEnum = externalCodeEnum; } } var result = new IntellisenseType { IsArray = !isDictionary && (isArray || isCollection), IsDictionary = isDictionary, IsOptional = isNullable, CodeName = effectiveTypeRef.AsString }; if (effectiveTypeRef.TypeKind == vsCMTypeRef.vsCMTypeRefCodeType && (effectiveTypeRef.CodeType.InfoLocation == vsCMInfoLocation.vsCMInfoLocationProject || (Options.AssumeExternalType == false && effectiveTypeRef.CodeType.InfoLocation == vsCMInfoLocation.vsCMInfoLocationExternal))) { try { result.ClientSideReferenceName = (codeClass != null && HasIntellisense(codeClass.ProjectItem, references) ? (GetNamespace(codeClass) + "." + Utility.CamelCaseClassName(GetClassName(codeClass))) : null) ?? (codeEnum != null && HasIntellisense(codeEnum.ProjectItem, references) ? (GetNamespace(codeEnum) + "." + Utility.CamelCaseClassName(codeEnum.Name)) : null); } catch (Exception) { } } else if (Options.AssumeExternalType && effectiveTypeRef.TypeKind == vsCMTypeRef.vsCMTypeRefCodeType && effectiveTypeRef.CodeType.InfoLocation == vsCMInfoLocation.vsCMInfoLocationExternal) { try { result.ClientSideReferenceName = (codeClass != null ? (GetNamespace(codeClass) + "." + Utility.CamelCaseClassName(GetClassName(codeClass))) : null) ?? (codeEnum != null ? (GetNamespace(codeEnum) + "." + Utility.CamelCaseClassName(codeEnum.Name)) : null); } catch (Exception) { } } else { result.ClientSideReferenceName = null; } if (!isPrimitive && codeClass != null && !traversedTypes.Contains(effectiveTypeRef.CodeType.FullName) && !isCollection) { traversedTypes.Add(effectiveTypeRef.CodeType.FullName); result.Shape = GetProperties(projectItem, definitionMapData, effectiveTypeRef.CodeType.Members, traversedTypes, references).ToList(); traversedTypes.Remove(effectiveTypeRef.CodeType.FullName); } return(result); } catch (InvalidCastException) { VSHelpers.WriteOnOutputWindow(string.Format("ERROR - Cannot find definition for {0}", typeName)); throw new ArgumentException(string.Format("Cannot find definition of {0}", typeName)); } }