public virtual void WriteTypescript(TsOutputer outputter) { foreach (var child in Children.Values.OrderBy(x => x.DisplayText)) { child.WriteTypescript(outputter); } }
public virtual void GetTypescriptComment(TsOutputer outputter) { if (string.IsNullOrEmpty(Summary)) { return; } outputter.AppendLine("/** " + Summary.Trim() + " */"); }
public override void WriteTypescript(TsOutputer outputter) { base.GetTypescriptComment(outputter); outputter.AppendLine("declare namespace " + DisplayText + " {"); outputter.IncreaseIndent(); base.WriteTypescript(outputter); outputter.DecreaseIndent(); outputter.AppendLine("}"); outputter.OutputBuilder.AppendLine(); }
public override void WriteTypescript(TsOutputer outputter) { if (Children.Count > 0 || IsReferenced) { base.GetTypescriptComment(outputter); outputter.AppendLine("interface " + DisplayText + GetInterfaceExtensionString() + " {"); outputter.IncreaseIndent(); base.WriteTypescript(outputter); outputter.DecreaseIndent(); outputter.AppendLine("}"); outputter.OutputBuilder.AppendLine(); } }
public override void WriteTypescript(TsOutputer outputter) { base.GetTypescriptComment(outputter); // TODO: const? outputter.AppendLine("enum " + DisplayText + " {"); outputter.IncreaseIndent(); base.WriteTypescript(outputter); // remove last comma int index = outputter.OutputBuilder.Length - 1; while (char.IsWhiteSpace(outputter.OutputBuilder[index])) { index--; } if (outputter.OutputBuilder[index] == ',') { outputter.OutputBuilder.Remove(index, 1); } outputter.DecreaseIndent(); outputter.AppendLine("}"); }
public override void WriteTypescript(TsOutputer outputter) { base.GetTypescriptComment(outputter); outputter.AppendLine(this.DisplayText + GetValueString() + ","); }
public static async Task <IEnumerable <TsCodeGenerationResult> > GenerateCode(Solution solution, IEnumerable <string> projects, ITypescriptGeneratorTargetProvider tgtProvider, bool wholeSolution) { _solution = solution; if (projects != null) { foreach (var projectFile in projects.Where(x => x.EndsWith(".csproj", StringComparison.OrdinalIgnoreCase))) { _projects.Enqueue(projectFile); } } if (_projects.Count == 0) { PopulateProjects(); } // Each project's contents are stored as a dictionary of namespaces (since they will be stored that way in file form for TS generation). Dictionary <string, CSharpNamespace> namespaces = new Dictionary <string, CSharpNamespace>(); Dictionary <string, CSharpReference> referencesPendingParse = new Dictionary <string, CSharpReference>(); HashSet <string> referenced = new HashSet <string>(); HashSet <string> parsedProjects = new HashSet <string>(StringComparer.OrdinalIgnoreCase); // Phase 1: go through all projects to parse their contents while (_projects.Count > 0) { var projName = _projects.Dequeue(); if (parsedProjects.Contains(projName)) { continue; } Project project = _solution.Projects.FirstOrDefault(x => x.FilePath != null && x.FilePath.Equals(projName, StringComparison.OrdinalIgnoreCase)); if (project != null) { var compUnit = project.GetCompilationAsync().Result; var context = new TsContext(); var output = new TsOutputer(); foreach (var st in compUnit.SyntaxTrees) { var semanticModel = compUnit.GetSemanticModel(st); var root = st.GetRoot(); var tsw = new TSWalker(st, output, context, semanticModel); tsw.Visit(root); // Collect the namespaces from this file and store them for the project foreach (var nsKvp in tsw.CSFile.Elements) { CSharpNamespace existingNsObj; if (namespaces.TryGetValue(nsKvp.Key, out existingNsObj)) { existingNsObj.Merge(nsKvp.Value); } else { nsKvp.Value.ProjectPath = project.FilePath; namespaces.Add(nsKvp.Key, nsKvp.Value); } } // get references needed by the file foreach (var refKvp in tsw.CSFile.GetReferences()) { referenced.Add(refKvp.Key); // TODO: get the namespace and the name of the reference string ns, name; Extensions.GetNamespaceAndName(refKvp.Key, out ns, out name); // try to get existing namespace CSharpNamespace existingNs; if (namespaces.TryGetValue(ns, out existingNs)) { // look for the reference in the namespace's children ICSharpFileElement fileEle; if (existingNs.Children.TryGetValue(name, out fileEle)) { var clsObj = fileEle as CSharpClass; if (clsObj != null) { clsObj.IsReferenced = true; } // move on. continue; } } // If we're at this point, either we haven't parsed anything to produce the namespace, // or the namespace doesn't contain the reference yet. // Either way, we need to store the reference off for future resolution if (!referencesPendingParse.ContainsKey(refKvp.Key)) { referencesPendingParse.Add(refKvp.Key, refKvp.Value); } } } // check the references pending parse and see if any have been parsed since the project parsing finished. var pendingParseKeys = referencesPendingParse.Keys.ToList(); foreach (var pendingKey in pendingParseKeys) { string ns, name; Extensions.GetNamespaceAndName(pendingKey, out ns, out name); // try to get existing namespace CSharpNamespace existingNs; if (namespaces.TryGetValue(ns, out existingNs)) { // look for the reference in the namespace's children ICSharpFileElement fileEle; if (existingNs.Children.TryGetValue(name, out fileEle)) { var clsObj = fileEle as CSharpClass; if (clsObj != null) { clsObj.IsReferenced = true; } // remove from pending referencesPendingParse.Remove(pendingKey); } } } parsedProjects.Add(projName); if (referencesPendingParse.Count > 0) { HashSet <string> refProjects = new HashSet <string>(StringComparer.OrdinalIgnoreCase); // Determine the projects that contain these items foreach (var refFile in referencesPendingParse.Values) { foreach (var location in refFile.DeclaringLocations) { string projPath = null; var temp = location; do { var tempDir = Path.GetDirectoryName(temp); var dirInfo = new DirectoryInfo(tempDir); var projFiles = dirInfo.GetFiles("*.csproj", SearchOption.TopDirectoryOnly); if (projFiles.Length == 1) { projPath = projFiles[0].FullName; } else if (projFiles.Length > 1) { // TODO: not sure what to do here } else { temp = tempDir; } }while (projPath == null); refProjects.Add(projPath); } } foreach (var refProj in refProjects) { _projects.Enqueue(refProj); } } } } // Phase 2: // go through all namespaces and mark files that are referenced. This is needed so we can exlude classes that have zero properties that aren't referenced foreach (var ns in namespaces) { // go through all children and mark referenced classes foreach (var clsEle in ns.Value.Children.Where(x => x.Value is CSharpClass)) { var clsNs = string.Format("{0}.{1}", ns.Key, clsEle.Key); if (referenced.Contains(clsNs)) { (clsEle.Value as CSharpClass).IsReferenced = true; } } } Dictionary <string, List <string> > projectReferenceFiles = new Dictionary <string, List <string> >(StringComparer.OrdinalIgnoreCase); List <TsCodeGenerationResult> resultFiles = new List <TsCodeGenerationResult>(); // Phase 3: // Group namespaces by project path, so that namespace files can be written for the appropriate project WriteMessage("Generating typings files..."); foreach (var projectGroup in namespaces.Values.GroupBy(x => x.ProjectPath, StringComparer.OrdinalIgnoreCase)) { List <string> generatedFiles = new List <string>(); foreach (var ns in projectGroup) { if (ns.ShouldWrite) { string filenameToWrite = null; if (tgtProvider != null) { filenameToWrite = tgtProvider.GetTargetFilename(ns.DisplayText, projectGroup.Key); } if (filenameToWrite == null) { filenameToWrite = GetDefaultTargetFilename(ns.DisplayText, projectGroup.Key); } TsOutputer outputter = new TsOutputer(); ns.WriteTypescript(outputter); StringBuilder sb = new StringBuilder(); var nsRefs = ns.GetReferences().Select(x => { string localNs, localName; Extensions.GetNamespaceAndName(x.Key, out localNs, out localName); return(localNs); }).Where(y => y != ns.DisplayText); HashSet <string> uniqueNsReferences = new HashSet <string>(nsRefs); if (uniqueNsReferences.Count > 0) { foreach (var reference in uniqueNsReferences.OrderBy(x => x)) { string containingProject = null; CSharpNamespace namespaceObj; if (namespaces.TryGetValue(reference, out namespaceObj)) { containingProject = namespaceObj.ProjectPath; } else { containingProject = projectGroup.Key; } string nsFilename = null; if (tgtProvider != null) { nsFilename = tgtProvider.GetTargetFilename(reference, containingProject); } if (nsFilename == null) { nsFilename = GetDefaultTargetFilename(reference, containingProject); } sb.AppendFormat("/// <reference path=\"{0}\" />\r\n", FileHelpers.RelativePath(filenameToWrite, nsFilename)); } sb.AppendLine(); } sb.Append(outputter.GetContent()); if (sb.Length > 0) { var fileResult = await FileHelpers.WriteAllTextRetry(filenameToWrite, sb.ToString(), tgtProvider.EnsureFileIsWritable); if (fileResult.ErrorMessage != null) { WriteMessage(fileResult.ErrorMessage); } resultFiles.Add(fileResult); generatedFiles.Add(filenameToWrite); } } } if (generatedFiles.Count > 0) { string referencesFilePath = null; if (tgtProvider != null) { referencesFilePath = tgtProvider.GetDefaultTargetReferencesFilename(projectGroup.Key); } if (referencesFilePath == null) { referencesFilePath = GetDefaultTargetReferencesFilename(projectGroup.Key); } List <string> existingList; if (projectReferenceFiles.TryGetValue(referencesFilePath, out existingList)) { existingList.AddRange(generatedFiles); } else { projectReferenceFiles.Add(referencesFilePath, new List <string>(generatedFiles)); } } } WriteMessage("Generating reference files..."); foreach (var refFile in projectReferenceFiles) { StringBuilder sb = new StringBuilder(); if (!wholeSolution && File.Exists(refFile.Key)) { sb.Append(File.ReadAllText(refFile.Key)); } bool write = false; Regex r = new Regex(@"/// <reference path=""(.*)"" />", RegexOptions.Multiline); HashSet <string> existingPaths = new HashSet <string>(r.Matches(sb.ToString()).Cast <Match>().Select(x => x.Groups[1].Value), StringComparer.OrdinalIgnoreCase); foreach (var refPath in refFile.Value.OrderBy(x => x)) { var relativePath = FileHelpers.RelativePath(refFile.Key, refPath); if (!existingPaths.Contains(relativePath)) { write = true; sb.AppendFormat("/// <reference path=\"{0}\" />\r\n", relativePath); } } if (write) { var fileResult = await FileHelpers.WriteAllTextRetry(refFile.Key, sb.ToString(), tgtProvider.EnsureFileIsWritable); if (fileResult.ErrorMessage != null) { WriteMessage(fileResult.ErrorMessage); } resultFiles.Add(fileResult); } } WriteMessage("TS File Generation complete!"); return(resultFiles); }
public TSWalker(SyntaxTree syntaxTree, TsOutputer output, TsContext context, SemanticModel model) { _csFile = new CSharpFile(syntaxTree.FilePath); this.model = model; this.context = context; }