public async Task <IActionResult> ShowMarkdownFile(string path) { if (_startupOptions.Mode != StartupMode.Try) { return(NotFound()); } if (string.IsNullOrEmpty(path)) { const string documentSvg = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M6,2A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6M6,4H13V9H18V20H6V4M8,12V14H16V12H8M8,16V18H13V16H8Z\" /></svg>"; var links = string.Join( "\n", _markdownProject.GetAllMarkdownFiles() .Select(f => $@"<li><a href=""{f.Path.Value.HtmlAttributeEncode()}"">{documentSvg}<span>{f.Path.Value}</span></a></li>")); return(Content(Index(links).ToString(), "text/html")); } var relativeFilePath = new RelativeFilePath(path); if (!_markdownProject.TryGetMarkdownFile(relativeFilePath, out var markdownFile)) { return(NotFound()); } var hostUrl = Request.GetUri(); var blocks = (await markdownFile.GetEditableAnnotatedCodeBlocks()).ToArray(); var maxEditorPerSession = blocks.Length > 0 ? blocks .GroupBy(b => b.Annotations.Session) .Max(editors => editors.Count()) : 0; var pipeline = _markdownProject.GetMarkdownPipelineFor(markdownFile.Path); var extension = pipeline.Extensions.FindExact <CodeBlockAnnotationExtension>(); if (extension != null) { extension.InlineControls = maxEditorPerSession <= 1; extension.EnablePreviewFeatures = _startupOptions.EnablePreviewFeatures; } var content = maxEditorPerSession <= 1 ? await OneColumnLayoutScaffold( $"{hostUrl.Scheme}://{hostUrl.Authority}", markdownFile) : await TwoColumnLayoutScaffold( $"{hostUrl.Scheme}://{hostUrl.Authority}", markdownFile); return(Content(content.ToString(), "text/html")); }
public async Task <IActionResult> ShowIndex() { const string documentSvg = "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M6,2A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6M6,4H13V9H18V20H6V4M8,12V14H16V12H8M8,16V18H13V16H8Z\" /></svg>"; var links = string.Join( "\n", _markdownProject.GetAllMarkdownFiles() .Select(f => $@"<li><a href=""{f.Path.Value.HtmlAttributeEncode()}"">{documentSvg}<span>{f.Path.Value}</span></a></li>")); return(Content(Index(links).ToString(), "text/html")); }
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 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}"); } } }