private async Task ProcessChildDirectories(Dictionary <string, DocumentationNode> resultNodes, DocumentationNode parentNode, string directoryPath) { foreach (var childDirectoryPath in Directory.GetDirectories(directoryPath)) { var directory = new DirectoryInfo(childDirectoryPath); var slug = SlugFormatter.ToSlug(directory.Name); var childNode = new DocumentationNode() { Title = directory.Name, Url = FilePathHelper.CombineVirtualPath(parentNode.Url, slug) }; childNode.UpdateDate = Directory.GetLastWriteTimeUtc(childDirectoryPath); await _fileWriterService.EnsureDirectoryExistsAsync(childNode.Url); await ProcessDirectory(childDirectoryPath, childNode); // Only add the node if it represents something in the document tree // i.e. skip static resource directories. if (childNode.Children.Any() || childNode.DocumentFilePath != null || childNode.RedirectTo != null) { resultNodes.Add(slug, childNode); } } }
private async Task ProcessFiles( Dictionary <string, DocumentationNode> resultNodes, DocumentationNode parentNode, string[] allFilePaths, Dictionary <string, string> redirects) { foreach (var filePath in allFilePaths) { // slug path var fileExtension = Path.GetExtension(filePath); var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath); var sluggedFileName = SlugFormatter.ToSlug(fileNameWithoutExtension); var sluggedFileNameWithExtension = Path.ChangeExtension(sluggedFileName, fileExtension); // skip the file if there's already a redirect if (redirects.Any(r => SlugFormatter.ToSlug(r.Key) == sluggedFileName)) { continue; } if (fileExtension == MARKDOWN_FILE_EXTENSION) { var destinationFilePath = FilePathHelper.CombineVirtualPath(parentNode.Url, sluggedFileNameWithExtension); var updateDate = File.GetLastWriteTimeUtc(filePath); // if we have a custom index file, map this to the container directory if (sluggedFileName == "index") { parentNode.DocumentFilePath = destinationFilePath; parentNode.UpdateDate = updateDate; } else { var node = new DocumentationNode() { Title = fileNameWithoutExtension, Url = FilePathHelper.CombineVirtualPath(parentNode.Url, sluggedFileName), DocumentFilePath = destinationFilePath, UpdateDate = updateDate }; resultNodes.Add(sluggedFileName, node); } await _fileWriterService.CopyFile(filePath, destinationFilePath); } else if (fileExtension != ".json") { // static files are served out of a separate directory var destinationDirectory = FilePathHelper.CombineVirtualPath(STATIC_FOLDER_NAME, parentNode.Url); var destinationPath = FilePathHelper.CombineVirtualPath(destinationDirectory, sluggedFileNameWithExtension); await _fileWriterService.EnsureDirectoryExistsAsync(destinationDirectory); await _fileWriterService.CopyFile(filePath, destinationPath); } // json files ignore, they are assumed to be config } }
private async Task ProcessDirectory(string directoryPath, DocumentationNode parentNode) { var allFilePaths = Directory.GetFiles(directoryPath); if (allFilePaths.Length == 0) { return; } var resultNodes = new Dictionary <string, DocumentationNode>(); // Read the redirects.json file if exists and map the contents var redirects = await ProcessRedirects(resultNodes, parentNode, allFilePaths); // if a directory level redirect was assigned, return. if (parentNode.RedirectTo != null) { return; } await ProcessFiles(resultNodes, parentNode, allFilePaths, redirects); await ProcessChildDirectories(resultNodes, parentNode, directoryPath); // Set ordering, set root file string[] tableOfContents = null; var tableOfContentsFile = allFilePaths.SingleOrDefault(f => Path.GetFileName(f) == "toc.json"); if (tableOfContentsFile != null) { tableOfContents = await DeserializeJsonFile <string[]>(tableOfContentsFile); } // If we have a toc file use it to filter out unwanted items and set ordering // otherwise order by title if (tableOfContents != null) { var redirectNodes = resultNodes .Where(n => n.Value.RedirectTo != null) .Select(n => n.Value); parentNode.Children = resultNodes .FilterAndOrderByKeys(tableOfContents.Select(SlugFormatter.ToSlug)) .Union(redirectNodes) .ToList(); } else { parentNode.Children = resultNodes .Select(r => r.Value) .OrderBy(r => r.Title) .ToList(); } }
private static async Task <Dictionary <string, string> > ProcessRedirects( Dictionary <string, DocumentationNode> resultNodes, DocumentationNode parentNode, string[] allFilePaths ) { Dictionary <string, string> redirects = null; var redirectsFile = allFilePaths.SingleOrDefault(f => Path.GetFileName(f) == "redirects.json"); DateTime updateDate; if (!string.IsNullOrEmpty(redirectsFile)) { redirects = await DeserializeJsonFile <Dictionary <string, string> >(redirectsFile); updateDate = File.GetLastWriteTimeUtc(redirectsFile); } else { redirects = new Dictionary <string, string>(); return(redirects); } var directoryRedirectRule = redirects.GetOrDefault("*"); if (directoryRedirectRule != null) { // If we have a directory level redirect rule, assign it to the // the directory node and return parentNode.RedirectTo = directoryRedirectRule; parentNode.UpdateDate = updateDate; return(redirects); } foreach (var redirect in redirects) { var slug = SlugFormatter.ToSlug(redirect.Key); var path = FilePathHelper.CombineVirtualPath(parentNode.Url, slug); var redirectTo = FilePathHelper.CombineVirtualPath(parentNode.Url, redirect.Value); var node = new DocumentationNode() { Title = redirect.Key, Url = path, RedirectTo = redirectTo, UpdateDate = updateDate }; resultNodes.Add(slug, node); } return(redirects ?? new Dictionary <string, string>()); }
public async Task GenerateAsync() { var version = _docGeneratorSettings.Version; var sourcePath = _docGeneratorSettings.SourcePath; var staticFileFolder = FilePathHelper.CombineVirtualPath(STATIC_FOLDER_NAME, version); await _fileWriterService.EnsureDirectoryExistsAsync(version); await _fileWriterService.EnsureDirectoryExistsAsync(staticFileFolder); if (_docGeneratorSettings.CleanDestination) { await _fileWriterService.ClearDirectoryAsync(version); await _fileWriterService.ClearDirectoryAsync(staticFileFolder); } var rootNode = new DocumentationNode() { Title = "Docs", Url = "/" + version, UpdateDate = DateTime.UtcNow }; // Copy files/directories recursively await ProcessDirectory(sourcePath, rootNode); // Write the completed table of contents file var serialized = JsonConvert.SerializeObject(rootNode, GetJsonSetting()); await _fileWriterService.WriteText(serialized, FilePathHelper.CombineVirtualPath(rootNode.Url, "toc.json")); // update the version manifest file in the root await UpdateVersionsAsync(); await PublishWebHook(); }