/// <summary> /// Builds the content for the markdown project page /// </summary> /// <param name="project">The markdown project item to be rendered</param> /// <returns>The markdown content</returns> public string BuildPage(MarkdownProject project) { DefaultTheme.ThemeLogger?.LogDebug("Building Main Api Page"); var homeBuilder = new MarkdownBuilder(); homeBuilder.HeaderWithLink(1, _options.RootTitle, project.To(project)); homeBuilder.AppendLine(); if (!string.IsNullOrEmpty(_options.RootSummary)) { homeBuilder .Header(2, "Summary") .AppendLine(_options.RootSummary) .AppendLine(); } homeBuilder.Header(2, "Namespaces").AppendLine(); foreach (var tempItem in project.AllItems.Values.Where(i => i.ItemType == MarkdownItemTypes.Namespace)) { var g = tempItem.As <MarkdownNamespace>(); if (!String.IsNullOrEmpty(g.FileName)) { homeBuilder.HeaderWithLink(3, g.FullName, project.To(g)); } else { homeBuilder.Header(3, g.Name); } homeBuilder.AppendLine(); if (!_options.ShowTypesOnRootPage) { continue; } foreach (var item in g.Types.OrderBy(x => x.Name)) { if (!String.IsNullOrEmpty(item.FileName)) { homeBuilder.List(Cleaner.CreateFullTypeWithLinks(project, item.InternalType, false, true)); } else { homeBuilder.List(item.Name); } if (!string.IsNullOrEmpty(item.Summary)) { homeBuilder.Tab().List(item.Summary); } } } homeBuilder.AppendLine(); return(homeBuilder.ToString()); }
public async Task Should_parse_markdown_file_and_set_package_with_fully_resolved_path() { var workingDir = TestAssets.SampleConsole; var packagePathRelativeToBaseDir = "src/sample/sample.csproj"; var dirAccessor = new InMemoryDirectoryAccessor(workingDir) { ("src/sample/Program.cs", ""), (packagePathRelativeToBaseDir, ""), ("docs/Readme.md", $@"```cs --project ../{packagePathRelativeToBaseDir} --source-file ../src/sample/Program.cs ```") }; var project = new MarkdownProject(dirAccessor, Default.PackageFinder); project.TryGetMarkdownFile(new RelativeFilePath("docs/Readme.md"), out var markdownFile).Should().BeTrue(); var htmlDocument = new HtmlDocument(); htmlDocument.LoadHtml((await markdownFile.ToHtmlContentAsync()).ToString()); var output = htmlDocument.DocumentNode .SelectSingleNode("//pre/code").Attributes["data-trydotnet-package"]; var fullProjectPath = dirAccessor.GetFullyQualifiedPath(new RelativeFilePath(packagePathRelativeToBaseDir)); output.Value.Should().Be(fullProjectPath.FullName); }
public DocumentationController(MarkdownProject markdownProject, StartupOptions startupOptions, PackageRegistry packageRegistry) { _markdownProject = markdownProject ?? throw new ArgumentNullException(nameof(markdownProject)); _startupOptions = startupOptions; _packageRegistry = packageRegistry ?? throw new ArgumentNullException(nameof(packageRegistry)); }
public async Task Returns_false_for_nonexistent_file() { var workingDir = TestAssets.SampleConsole; var dirAccessor = new InMemoryDirectoryAccessor(workingDir); var project = new MarkdownProject(dirAccessor, await Default.PackageRegistry.ValueAsync()); var path = new RelativeFilePath("DOESNOTEXIST"); project.TryGetMarkdownFile(path, out _).Should().BeFalse(); }
public void Returns_false_for_nonexistent_file() { var workingDir = TestAssets.SampleConsole; var dirAccessor = new InMemoryDirectoryAccessor(workingDir); var project = new MarkdownProject(dirAccessor, PackageRegistry.CreateForHostedMode()); var path = new RelativeFilePath("DOESNOTEXIST"); project.TryGetMarkdownFile(path, out _).Should().BeFalse(); }
public static MarkdownProject Load(string searchArea, string namespaceMatch) { List <MarkdownType> types = new List <MarkdownType>(); MarkdownProject project = new MarkdownProject(); AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; var matcher = new Matcher(); foreach (var searchPath in searchArea.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { matcher.AddInclude(searchPath); } var rootDir = Directory.GetCurrentDirectory(); var results = matcher.GetResultsInFullPath(rootDir); Constants.Logger?.LogInformation($"Found {results.Count()} dlls from {rootDir} using {searchArea}"); List <string> processedDlls = new List <string>(); foreach (var dllPath in results) { var dllName = Path.GetFileName(dllPath); Constants.Logger?.LogInformation("Loading Dll: {dllName}", dllPath); if (processedDlls.Contains(dllName)) { Constants.Logger?.LogWarning("Duplicate Dll: {dllName}", dllName); continue; } try { if (File.Exists(dllPath) && Path.GetExtension(dllPath) == ".dll") { LoadDll(dllPath, namespaceMatch); processedDlls.Add(dllName); } else { Constants.Logger?.LogError($"Failed to find {dllPath} dll"); } } catch (Exception e) { Constants.Logger?.LogError(e, "Failed to Load {dllName}", dllPath); } } return(project); }
public void TestSetup() { _project = MarkdownApiGenerator.GenerateProject("./igloo15.MarkdownApi.Tests.dll", null); _project.Build(new DefaultTheme(new DefaultOptions { BuildNamespacePages = true, BuildTypePages = true, RootFileName = "README.md", RootTitle = "API", RootSummary = "The Root Page Summary", ShowParameterNames = true }), @".\testdocs" ); }
public static async Task <int> Do( PublishOptions publishOptions, IConsole console, StartupOptions startupOptions = null, WriteOutput writeOutput = null ) { writeOutput ??= (path, content) => File.WriteAllText(path, content); var sourceDirectoryAccessor = publishOptions.RootDirectory; var packageRegistry = PackageRegistry.CreateForTryMode(sourceDirectoryAccessor); var markdownProject = new MarkdownProject( sourceDirectoryAccessor, packageRegistry, startupOptions); var markdownFiles = markdownProject.GetAllMarkdownFiles().ToArray(); if (markdownFiles.Length == 0) { console.Error.WriteLine($"No markdown files found under {sourceDirectoryAccessor.GetFullyQualifiedRoot()}"); return(-1); } var targetDirectoryAccessor = publishOptions.TargetDirectory; var targetIsSubDirectoryOfSource = targetDirectoryAccessor.IsSubDirectoryOf(sourceDirectoryAccessor); foreach (var markdownFile in markdownFiles) { var markdownFilePath = markdownFile.Path; var fullSourcePath = sourceDirectoryAccessor.GetFullyQualifiedPath(markdownFilePath); if (targetIsSubDirectoryOfSource && fullSourcePath.IsChildOf(targetDirectoryAccessor)) { continue; } var(document, newLine) = ParseMarkdownDocument(markdownFile); var rendered = await Render(publishOptions.Format, document, newLine); var targetPath = WriteTargetFile(rendered, markdownFilePath, targetDirectoryAccessor, publishOptions, writeOutput); console.Out.WriteLine($"Published '{fullSourcePath}' to {targetPath}"); } return(0); }
public async Task Returns_list_of_all_relative_paths_to_all_markdown_files() { var dirAccessor = new InMemoryDirectoryAccessor() { ("Readme.md", ""), ("Subdirectory/Tutorial.md", ""), ("Program.cs", "") }; var project = new MarkdownProject(dirAccessor, await Default.PackageRegistry.ValueAsync()); var files = project.GetAllMarkdownFiles(); files.Should().HaveCount(2); files.Should().Contain(f => f.Path.Value.Equals("./Readme.md")); files.Should().Contain(f => f.Path.Value.Equals("./Subdirectory/Tutorial.md")); }
public void Returns_list_of_all_relative_paths_to_all_markdown_files() { var workingDir = TestAssets.SampleConsole; var dirAccessor = new InMemoryDirectoryAccessor(workingDir) { ("Readme.md", ""), ("Subdirectory/Tutorial.md", ""), ("Program.cs", "") }; var project = new MarkdownProject(dirAccessor, Default.PackageFinder); var files = project.GetAllMarkdownFiles(); files.Should().HaveCount(2); files.Should().Contain(f => f.Path.Value.Equals("./Readme.md")); files.Should().Contain(f => f.Path.Value.Equals("./Subdirectory/Tutorial.md")); }
public MarkdownProcessingContext( IDirectoryAccessor rootDirectory, IDefaultCodeBlockAnnotations defaultAnnotations = null, WriteFile writeFile = null, IConsole console = null) { RootDirectory = rootDirectory; Console = console ?? new SystemConsole(); var packageRegistry = PackageRegistry.CreateForTryMode(rootDirectory); Project = new MarkdownProject( rootDirectory, packageRegistry, defaultAnnotations ?? new DefaultCodeBlockAnnotations()); _lazyWorkspaceServer = new Lazy <IWorkspaceServer>(() => new WorkspaceServerMultiplexer(packageRegistry)); WriteFile = writeFile ?? File.WriteAllText; }
public static async Task <int> Do( VerifyOptions verifyOptions, IConsole console, StartupOptions startupOptions = null) { var directoryAccessor = verifyOptions.RootDirectory; var packageRegistry = PackageRegistry.CreateForTryMode(directoryAccessor); var markdownProject = new MarkdownProject( directoryAccessor, packageRegistry, startupOptions); var errorCount = 0; var workspaceServer = new Lazy <IWorkspaceServer>(() => new WorkspaceServerMultiplexer(packageRegistry)); var markdownFiles = markdownProject.GetAllMarkdownFiles().ToArray(); if (markdownFiles.Length == 0) { console.Error.WriteLine($"No markdown files found under {directoryAccessor.GetFullyQualifiedRoot()}"); return(-1); } foreach (var markdownFile in markdownFiles) { var fullName = directoryAccessor.GetFullyQualifiedPath(markdownFile.Path).FullName; var markdownFileDirectoryAccessor = directoryAccessor.GetDirectoryAccessorForRelativePath(markdownFile.Path.Directory); console.Out.WriteLine(); console.Out.WriteLine(fullName); console.Out.WriteLine(new string('-', fullName.Length)); var codeLinkBlocks = await markdownFile.GetAnnotatedCodeBlocks(); var sessions = codeLinkBlocks.GroupBy(block => block.Annotations?.Session); foreach (var session in sessions) { if (session.Select(block => block.ProjectOrPackageName()).Distinct().Count() != 1) { SetError(); console.Out.WriteLine($"Session cannot span projects or packages: --session {session.Key}"); continue; } foreach (var codeLinkBlock in session) { ReportCodeLinkageResults(codeLinkBlock, markdownFileDirectoryAccessor); } Console.ResetColor(); if (!session.Any(block => block.Diagnostics.Any())) { var(buffersToInclude, filesToInclude) = await markdownFile.GetIncludes(markdownFileDirectoryAccessor); await ReportCompileResults( session, markdownFile, filesToInclude, buffersToInclude, markdownFileDirectoryAccessor); } Console.ResetColor(); } } if (errorCount > 0) { SetError(false); } else { SetOk(); } console.Out.WriteLine($"\n\ndotnet try verify found {errorCount} error(s)"); Console.ResetColor(); return(errorCount == 0 ? 0 : 1); void SetError(bool incrementCount = true) { Console.ForegroundColor = ConsoleColor.Red; if (incrementCount) { errorCount++; } } void SetOk() { Console.ForegroundColor = ConsoleColor.Green; } async Task ReportCompileResults( IGrouping <string, AnnotatedCodeBlock> session, MarkdownFile markdownFile, Dictionary <string, File[]> filesToInclude, IReadOnlyDictionary <string, Buffer[]> buffersToInclude, IDirectoryAccessor accessor) { var description = session.Count() == 1 || string.IsNullOrWhiteSpace(session.Key) ? $"region \"{session.Select(s => s.Annotations.Region).Distinct().First()}\"" : $"session \"{session.Key}\""; console.Out.WriteLine($"\n Compiling samples for {description}\n"); var projectOrPackageName = session .Select(b => b.ProjectOrPackageName()) .FirstOrDefault(name => !string.IsNullOrWhiteSpace(name)); var language = session .Select(b => b.Language()) .FirstOrDefault(name => !string.IsNullOrWhiteSpace(name)); if (!ProjectIsCompatibleWithLanguage(new UriOrFileInfo(projectOrPackageName), language)) { SetError(); console.Out.WriteLine($" Build failed as project {projectOrPackageName} is not compatible with language {language}"); } var editableCodeBlocks = session.Where(b => b.Annotations.Editable).ToList(); var buffers = editableCodeBlocks .Select(block => block.GetBufferAsync(accessor, markdownFile)) .ToList(); var files = new List <File>(); if (filesToInclude.TryGetValue("global", out var globalIncludes)) { files.AddRange(globalIncludes); } if (!string.IsNullOrWhiteSpace(session.Key) && filesToInclude.TryGetValue(session.Key, out var sessionIncludes)) { files.AddRange(sessionIncludes); } if (buffersToInclude.TryGetValue("global", out var globalSessionBuffersToInclude)) { buffers.AddRange(globalSessionBuffersToInclude); } if (!string.IsNullOrWhiteSpace(session.Key) && buffersToInclude.TryGetValue(session.Key, out var localSessionBuffersToInclude)) { buffers.AddRange(localSessionBuffersToInclude); } var workspace = new Workspace( workspaceType: projectOrPackageName, language: language, files: files.ToArray(), buffers: buffers.ToArray()); var mergeTransformer = new CodeMergeTransformer(); var inliningTransformer = new BufferInliningTransformer(); var processed = await mergeTransformer.TransformAsync(workspace); processed = await inliningTransformer.TransformAsync(processed); processed = new Workspace(usings: processed.Usings, workspaceType: processed.WorkspaceType, language: processed.Language, files: processed.Files); var result = await workspaceServer.Value.Compile(new WorkspaceRequest(processed)); var projectDiagnostics = result.GetFeature <ProjectDiagnostics>() .Where(e => e.Severity == DiagnosticSeverity.Error) .ToArray(); if (projectDiagnostics.Any()) { SetError(); console.Out.WriteLine($" Build failed for project {projectOrPackageName}"); foreach (var diagnostic in projectDiagnostics) { console.Out.WriteLine($"\t\t{diagnostic.Location}: {diagnostic.Message}"); } } else { var symbol = !result.Succeeded ? "X" : "✓"; if (result.Succeeded) { SetOk(); console.Out.WriteLine($" {symbol} No errors found within samples for {description}"); } else { SetError(); console.Out.WriteLine($" {symbol} Errors found within samples for {description}"); foreach (var diagnostic in result.GetFeature <Diagnostics>()) { console.Out.WriteLine($"\t\t{diagnostic.Message}"); } } } } void ReportCodeLinkageResults( AnnotatedCodeBlock codeLinkBlock, IDirectoryAccessor accessor) { var diagnostics = codeLinkBlock.Diagnostics.ToArray(); Console.ResetColor(); console.Out.WriteLine(" Checking Markdown..."); if (diagnostics.Any()) { SetError(); } else { Console.ForegroundColor = ConsoleColor.Green; } var blockOptions = (LocalCodeBlockAnnotations)codeLinkBlock.Annotations; var file = blockOptions?.SourceFile ?? blockOptions?.DestinationFile; var fullyQualifiedPath = file != null ? accessor.GetFullyQualifiedPath(file).FullName : "UNKNOWN"; var project = codeLinkBlock.ProjectOrPackageName() ?? "UNKNOWN"; var symbol = diagnostics.Any() ? "X" : "✓"; console.Out.WriteLine($" {symbol} Line {codeLinkBlock.Line + 1}:\t{fullyQualifiedPath} (in project {project})"); foreach (var diagnostic in diagnostics) { console.Out.WriteLine($"\t\t{diagnostic}"); } } }
public DocumentationController(MarkdownProject markdownProject, StartupOptions startupOptions) { _markdownProject = markdownProject ?? throw new ArgumentNullException(nameof(markdownProject)); _startupOptions = startupOptions; }
/// <summary> /// Builds Project Pages with the given MarkdownProject Item /// </summary> /// <param name="item">The MarkdownProject item to build the page with</param> /// <returns>A string of the markdown content or "" if no page created</returns> public string BuildPage(MarkdownProject item) { return(_projectBuilder.BuildPage(item)); }