void UpdateExistingLibraries(XDocument docs, HashSet <string> seenLibraries) { foreach (XElement types in docs.Root.Elements("Types")) { XAttribute library = types.Attribute("Library"); HashSet <string> libraryTypes; if (library == null || !libraries.TryGetValue(library.Value, out libraryTypes)) { continue; } seenLibraries.Add(library.Value); var seenTypes = new HashSet <string> (); foreach (XElement type in types.Elements("Type").ToList()) { XAttribute fullName = type.Attribute("FullName"); string typeName = fullName == null ? null : XmlDocUtils.ToEscapedTypeName(fullName.Value); if (typeName == null || !libraryTypes.Contains(typeName)) { continue; } type.Remove(); seenTypes.Add(typeName); types.Add(LoadType(typeName, library.Value)); } foreach (string typeName in libraryTypes.Except(seenTypes)) { types.Add(LoadType(typeName, library.Value)); } } }
void ProcessFiles(Options opts, string format, List <string> files) { foreach (var basePath in files.Select(f => Path.Combine(Path.GetDirectoryName(f), Path.GetFileNameWithoutExtension(f))) .Distinct()) { string treeFile = basePath + ".tree"; string zipFile = basePath + ".zip"; if (!Exists(treeFile) || !Exists(zipFile)) { continue; } string outDir = opts.OutputDirectory != null ? Path.Combine(opts.OutputDirectory, Path.GetFileName(basePath)) : XmlDocUtils.GetCacheDirectory(basePath); if (!opts.ForceUpdate && Directory.Exists(outDir) && MaxWriteTime(treeFile, zipFile) < Directory.GetLastWriteTime(outDir)) { continue; } Message(TraceLevel.Warning, "Processing files: {0}, {1}", treeFile, zipFile); Directory.CreateDirectory(outDir); ExtractZipFile(zipFile, outDir); GenerateCache(opts, basePath, format, outDir); } }
public override void Run(IEnumerable <string> args) { string dir = null; bool forceUpdate = false; var options = new OptionSet() { { "force-update", "Always generate new files. If not specified, will only generate " + "files if the write time of the output directory is older than the " + "write time of the source .tree/.zip files.", v => forceUpdate = v != null }, { "o|out=", "The {PREFIX} to place the generated files and directories. " + "Default: \"`dirname FILE`/cache/\".\n" + "Underneath {PREFIX}, `basename FILE .tree` directories will be " + "created which will contain the pre-generated HTML content.", v => dir = v }, }; List <string> files = Parse(options, args, "export-html-webdoc", "[OPTIONS]+ FILES", "Export mdoc documentation within FILES to HTML for use by ASP.NET webdoc.\n\n" + "FILES are .tree or .zip files as produced by 'mdoc assemble'."); if (files == null) { return; } if (files.Count == 0) { Error("No files specified."); } HelpSource.use_css = true; HelpSource.FullHtml = false; SettingsHandler.Settings.EnableEditing = false; foreach (var basePath in files.Select(f => Path.Combine(Path.GetDirectoryName(f), Path.GetFileNameWithoutExtension(f))) .Distinct()) { string treeFile = basePath + ".tree"; string zipFile = basePath + ".zip"; if (!Exists(treeFile) || !Exists(zipFile)) { continue; } string outDir = dir != null ? Path.Combine(dir, Path.GetFileName(basePath)) : XmlDocUtils.GetCacheDirectory(basePath); if (!forceUpdate && Directory.Exists(outDir) && MaxWriteTime(treeFile, zipFile) < Directory.GetLastWriteTime(outDir)) { continue; } Message(TraceLevel.Warning, "Processing files: {0}, {1}", treeFile, zipFile); Directory.CreateDirectory(outDir); ExtractZipFile(zipFile, outDir); GenerateCache(basePath, treeFile, outDir); } }
void GenerateCache(string basePath, string treeFile, string outDir) { Tree tree = new Tree(null, treeFile); RootTree docRoot = RootTree.LoadTree(); string helpSourceName = Path.GetFileName(basePath); HelpSource hs = docRoot.HelpSources.Cast <HelpSource> () .FirstOrDefault(h => h.Name == helpSourceName); if (hs == null) { throw new Exception("Only installed .tree and .zip files are supported."); } foreach (Node node in tree.TraverseDepthFirst <Node, Node> (t => t, t => t.Nodes.Cast <Node> ())) { var url = node.URL; Message(TraceLevel.Info, "\tProcessing URL: {0}", url); if (string.IsNullOrEmpty(url)) { continue; } var file = XmlDocUtils.GetCachedFileName(outDir, url); using (var o = File.AppendText(file)) { Node _; // Sometimes the HelpSource won't directly support a url. // Case in point: the Tree will contain N:Enter.Namespace.Here nodes // which aren't supported by HelpSource.GetText. // If this happens, docRoot.RenderUrl() works. // (And no, we can't always use docRoot.RenderUrl() for URLs like // "ecma:0#Foo/", as that'll just grab the 0th stream contents from // the first EcmaHelpSource found... string contents = hs.GetText(url, out _) ?? docRoot.RenderUrl(url, out _); o.Write(contents); } } }
void GenerateCache(Options opts, string basePath, string format, string outDir) { var hs = RootTree.GetHelpSource(format, basePath); if (hs == null) { Error("Unable to find a HelpSource for provider '{0}' and file '{1}.tree'.", format, basePath); } var tree = hs.Tree; RootTree docRoot = null; if (!opts.UseSystemSources) { docRoot = RootTree.LoadTree(null, null, opts.Sources); } else { docRoot = RootTree.LoadTree(); foreach (var source in opts.Sources) { docRoot.AddSourceFile(source); } } hs.RootTree = docRoot; string helpSourceName = Path.GetFileName(basePath); foreach (Node node in tree.TraverseDepthFirst <Node, Node> (t => t, t => t.Nodes.Cast <Node> ())) { var url = node.URL; Message(TraceLevel.Info, "\tProcessing URL: {0}", url); if (string.IsNullOrEmpty(url)) { continue; } var file = XmlDocUtils.GetCachedFileName(outDir, url); using (var o = File.AppendText(file)) { Node _; string contents = hs.GetText(url, out _) ?? hs.RenderNamespaceLookup(url, out _); o.Write(contents); } } }
static string MakeArgs(XmlElement member) { XmlNodeList parameters = member.SelectNodes("Parameters/Parameter"); if (parameters.Count == 0) { return(""); } StringBuilder args = new StringBuilder(); args.Append("("); args.Append(XmlDocUtils.ToTypeName(parameters [0].Attributes ["Type"].Value, member)); for (int i = 1; i < parameters.Count; ++i) { args.Append(","); args.Append(XmlDocUtils.ToTypeName(parameters [i].Attributes ["Type"].Value, member)); } args.Append(")"); return(args.ToString()); }
static string GetCref(XmlElement member) { string typeName = XmlDocUtils.ToEscapedTypeName(member.SelectSingleNode("/Type/@FullName").InnerText); if (member.Name == "Type") { return("T:" + typeName); } string memberType = member.SelectSingleNode("MemberType").InnerText; switch (memberType) { case "Constructor": return("C:" + typeName + MakeArgs(member)); case "Event": return("E:" + typeName + "." + XmlDocUtils.ToEscapedMemberName(member.GetAttribute("MemberName"))); case "Field": return("F:" + typeName + "." + XmlDocUtils.ToEscapedMemberName(member.GetAttribute("MemberName"))); case "Method": { string name = "M:" + typeName + "." + XmlDocUtils.ToEscapedMemberName(member.GetAttribute("MemberName")) + MakeArgs(member); if (member.GetAttribute("MemberName") == "op_Implicit" || member.GetAttribute("MemberName") == "op_Explicit") { name += "~" + XmlDocUtils.ToTypeName(member.SelectSingleNode("ReturnValue/ReturnType").InnerText, member); } return(name); } case "Property": return("P:" + typeName + "." + XmlDocUtils.ToEscapedMemberName(member.GetAttribute("MemberName")) + MakeArgs(member)); default: throw new NotSupportedException("MemberType '" + memberType + "' is not supported."); } }
void ProcessDirectories(List <string> sourceDirectories) { if (sourceDirectories.Count == 0 || opts.dest == null || opts.dest == "") { throw new ApplicationException("The source and dest options must be specified."); } Directory.CreateDirectory(opts.dest); // Load the stylesheets, overview.xml, and resolver XslCompiledTransform overviewxsl = LoadTransform("overview.xsl", sourceDirectories); XslCompiledTransform stylesheet = LoadTransform("stylesheet.xsl", sourceDirectories); XslCompiledTransform template; if (opts.template == null) { template = LoadTransform("defaulttemplate.xsl", sourceDirectories); } else { try { XmlDocument templatexsl = new XmlDocument(); templatexsl.Load(opts.template); template = new XslCompiledTransform(DebugOutput); template.Load(templatexsl); } catch (Exception e) { throw new ApplicationException("There was an error loading " + opts.template, e); } } XmlDocument overview = GetOverview(sourceDirectories); ArrayList extensions = GetExtensionMethods(overview); // Create the master page XsltArgumentList overviewargs = new XsltArgumentList(); overviewargs.AddParam("Index", "", overview.CreateNavigator()); var regenIndex = ShouldRegenIndexes(opts, overview, sourceDirectories); if (regenIndex) { overviewargs.AddParam("ext", "", opts.ext); overviewargs.AddParam("basepath", "", "./"); Generate(overview, overviewxsl, overviewargs, opts.dest + "/index." + opts.ext, template, sourceDirectories); overviewargs.RemoveParam("basepath", ""); } overviewargs.AddParam("basepath", "", "../"); // Create the namespace & type pages XsltArgumentList typeargs = new XsltArgumentList(); typeargs.AddParam("ext", "", opts.ext); typeargs.AddParam("basepath", "", "../"); typeargs.AddParam("Index", "", overview.CreateNavigator()); foreach (XmlElement ns in overview.SelectNodes("Overview/Types/Namespace")) { string nsname = ns.GetAttribute("Name"); if (opts.onlytype != null && !opts.onlytype.StartsWith(nsname + ".")) { continue; } System.IO.DirectoryInfo d = new System.IO.DirectoryInfo(opts.dest + "/" + nsname); if (!d.Exists) { d.Create(); } // Create the NS page string nsDest = opts.dest + "/" + nsname + "/index." + opts.ext; if (regenIndex) { overviewargs.AddParam("namespace", "", nsname); Generate(overview, overviewxsl, overviewargs, nsDest, template, sourceDirectories); overviewargs.RemoveParam("namespace", ""); } foreach (XmlElement ty in ns.SelectNodes("Type")) { string typename, typefile, destfile; GetTypePaths(opts, ty, out typename, out typefile, out destfile); if (DestinationIsNewer(typefile, destfile)) { // target already exists, and is newer. why regenerate? continue; } XmlDocument typexml = new XmlDocument(); typexml.Load(typefile); PreserveMembersInVersions(typexml); if (extensions != null) { DocLoader loader = CreateDocLoader(overview); XmlDocUtils.AddExtensionMethods(typexml, extensions, loader); } Console.WriteLine(nsname + "." + typename); Generate(typexml, stylesheet, typeargs, destfile, template, sourceDirectories); } } }
private static void Process(string basepath, Dictionary <string, XmlElement> outputfiles, XmlDocument nsSummaries, bool implicitFiles) { if (System.Environment.CurrentDirectory == System.IO.Path.GetFullPath(basepath) && implicitFiles) { Console.WriteLine("Don't run this tool from your documentation directory, since some files could be accidentally overwritten."); return; } XmlDocument index_doc = new XmlDocument(); index_doc.Load(Path.Combine(basepath, "index.xml")); XmlElement index = index_doc.DocumentElement; foreach (XmlElement assmbly in index.SelectNodes("Assemblies/Assembly")) { string assemblyName = assmbly.GetAttribute("Name"); if (outputfiles.ContainsKey(assemblyName)) { continue; } XmlDocument output = new XmlDocument(); XmlElement output_root = output.CreateElement("doc"); output.AppendChild(output_root); XmlElement output_assembly = output.CreateElement("assembly"); output_root.AppendChild(output_assembly); XmlElement output_assembly_name = output.CreateElement("name"); output_assembly.AppendChild(output_assembly_name); output_assembly_name.InnerText = assemblyName; XmlElement members = output.CreateElement("members"); output_root.AppendChild(members); outputfiles.Add(assemblyName, members); } foreach (XmlElement nsnode in index.SelectNodes("Types/Namespace")) { string ns = nsnode.GetAttribute("Name"); foreach (XmlElement typedoc in nsnode.SelectNodes("Type")) { string typename = typedoc.GetAttribute("Name"); XmlDocument type = new XmlDocument(); type.Load(Path.Combine(Path.Combine(basepath, ns), typename) + ".xml"); string assemblyname = type.SelectSingleNode("Type/AssemblyInfo/AssemblyName").InnerText; XmlElement members = outputfiles [assemblyname]; if (members == null) { continue; // assembly is strangely not listed in the index } string typeName = XmlDocUtils.ToEscapedTypeName(type.SelectSingleNode("Type/@FullName").InnerText); CreateMember("T:" + typeName, type.DocumentElement, members); foreach (XmlElement memberdoc in type.SelectNodes("Type/Members/Member")) { string name = typeName; switch (memberdoc.SelectSingleNode("MemberType").InnerText) { case "Constructor": name = "C:" + name + MakeArgs(memberdoc); break; case "Method": name = "M:" + name + "." + XmlDocUtils.ToEscapedMemberName(memberdoc.GetAttribute("MemberName")) + MakeArgs(memberdoc); if (memberdoc.GetAttribute("MemberName") == "op_Implicit" || memberdoc.GetAttribute("MemberName") == "op_Explicit") { name += "~" + XmlDocUtils.ToTypeName(memberdoc.SelectSingleNode("ReturnValue/ReturnType").InnerText, memberdoc); } break; case "Property": name = "P:" + name + "." + XmlDocUtils.ToEscapedMemberName(memberdoc.GetAttribute("MemberName")) + MakeArgs(memberdoc); break; case "Field": name = "F:" + name + "." + XmlDocUtils.ToEscapedMemberName(memberdoc.GetAttribute("MemberName")); break; case "Event": name = "E:" + name + "." + XmlDocUtils.ToEscapedMemberName(memberdoc.GetAttribute("MemberName")); break; } CreateMember(name, memberdoc, members); } } } foreach (XmlElement nsnode in index.SelectNodes("Types/Namespace")) { AddNamespaceSummary(nsSummaries, basepath, nsnode.GetAttribute("Name")); } }