Esempio n. 1
0
        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);
            }
        }
Esempio n. 3
0
 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);
     }
 }
        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}");
                }
            }
        }
        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;
            }
        }
 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);
     }
 }
Esempio n. 7
0
        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]);
        }
        /// <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(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));
            }
        }
Esempio n. 11
0
        /// <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());
        }
Esempio n. 12
0
        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));
            }
        }