public static IsRelativePath ( string path ) : bool | ||
path | string | |
return | bool |
private ImmutableDictionary <string, ImmutableList <LinkSourceInfo> > GetFileLinkSource(FileAndType ft, HtmlDocument doc) { var fileLinkSources = new Dictionary <string, List <LinkSourceInfo> >(); foreach (var pair in (from n in doc.DocumentNode.Descendants() where !string.Equals(n.Name, "xref", StringComparison.OrdinalIgnoreCase) from attr in n.Attributes where string.Equals(attr.Name, "src", StringComparison.OrdinalIgnoreCase) || string.Equals(attr.Name, "href", StringComparison.OrdinalIgnoreCase) where !string.IsNullOrWhiteSpace(attr.Value) select new { Node = n, Attr = attr }).ToList()) { string linkFile; string anchor = null; var link = pair.Attr; if (TypeForwardedToPathUtility.IsRelativePath(link.Value)) { var index = link.Value.IndexOfAny(UriFragmentOrQueryString); if (index == -1) { linkFile = link.Value; } else if (index == 0) { continue; } else { linkFile = link.Value.Remove(index); anchor = link.Value.Substring(index); } var path = (TypeForwardedToRelativePath)ft.File + (TypeForwardedToRelativePath)linkFile; string file = path.GetPathFromWorkingFolder().UrlDecode(); if (SourceFiles.ContainsKey(file)) { link.Value = file; if (!string.IsNullOrEmpty(anchor) && string.Equals(link.Name, "href", StringComparison.OrdinalIgnoreCase)) { pair.Node.SetAttributeValue("anchor", anchor); } } List <LinkSourceInfo> sources; if (!fileLinkSources.TryGetValue(file, out sources)) { sources = new List <LinkSourceInfo>(); fileLinkSources[file] = sources; } sources.Add(new LinkSourceInfo { Target = file, Anchor = anchor, SourceFile = pair.Node.GetAttributeValue("sourceFile", null), LineNumber = pair.Node.GetAttributeValue("sourceStartLineNumber", 0), }); } } return(fileLinkSources.ToImmutableDictionary(x => x.Key, x => x.Value.ToImmutableList())); }
private static ChangeList ParseCore(string tsvFile, string baseDir) { var result = new ChangeList(); bool hasError = false; foreach (var line in File.ReadLines(tsvFile)) { if (string.IsNullOrWhiteSpace(line)) { continue; } var columns = line.Split('\t'); if (columns.Length >= 2) { if (string.Equals(columns[0], "<from>", StringComparison.OrdinalIgnoreCase)) { result.From = columns[1]; continue; } if (string.Equals(columns[0], "<to>", StringComparison.OrdinalIgnoreCase)) { result.To = columns[1]; continue; } string path; if (TypeForwardedToPathUtility.IsRelativePath(columns[0])) { path = columns[0]; } else { path = TypeForwardedToPathUtility.MakeRelativePath(baseDir, columns[0]); } if (path != null) { ChangeKind kind; if (Enum.TryParse(columns[1], true, out kind)) { if (kind != ChangeKind.Deleted) { if (!File.Exists(Path.Combine(baseDir, path))) { Logger.LogError($"File:{path} not existed."); hasError = true; continue; } } result.Add(path, kind); continue; } } } Logger.LogWarning($"Ignore unknown line: {line}"); } if (hasError) { throw new DocfxException($"Some error ocurred while parsing changelist file: {tsvFile}."); } return(result); }
private void WriteLine(ILogItem item) { if (item == null) { throw new ArgumentNullException(nameof(item)); } if (item.File == null) { return; } string fileFromWorkingDir = TypeForwardedToStringExtension.BackSlashToForwardSlash(item.File); if (!TypeForwardedToPathUtility.IsRelativePath(item.File)) { fileFromWorkingDir = TypeForwardedToPathUtility.MakeRelativePath(EnvironmentContext.BaseDirectory, item.File); } List <LogItem> logsPerFile; if (!_logs.TryGetValue(fileFromWorkingDir, out logsPerFile)) { logsPerFile = _logs[fileFromWorkingDir] = new List <LogItem>(); } logsPerFile.Add(new LogItem { File = TypeForwardedToStringExtension.BackSlashToForwardSlash(item.File), Line = item.Line, LogLevel = item.LogLevel, Message = item.Message, Phase = item.Phase, }); }
/// <summary> /// Append default extension to href by condition /// </summary> /// <param name="href">original href string</param> /// <param name="defaultExtension">default extension to append</param> /// <returns>Href with default extension appended</returns> private AppendDefaultExtensionResult AppendDefaultExtension(string href, string defaultExtension, IMarkdownContext context, string rawMarkdown, string line) { // If the context doesn't have necessary info, return the original href if (!context.Variables.ContainsKey("path")) { return(new AppendDefaultExtensionResult(false, href, null)); } var currentFilePath = (string)context.Variables["path"]; try { if (!TypeForwardedToPathUtility.IsRelativePath(href)) { return(new AppendDefaultExtensionResult(false, href, null)); } } catch (ArgumentException) { Logger.LogWarning($"Invalid reference {href} in file: {currentFilePath}. Raw: {rawMarkdown}", null, currentFilePath, line); return(new AppendDefaultExtensionResult(false, href, null)); } var index = href.IndexOf('#'); if (index == -1) { href = href.TrimEnd('/'); var extension = Path.GetExtension(href); // Regard all the relative path with no extension as markdown file that missing .md if (string.IsNullOrEmpty(extension)) { return(new AppendDefaultExtensionResult(true, $"{href}{defaultExtension}", true)); } else { bool isMarkdownFile = extension.Equals(MarkdownExtension, StringComparison.OrdinalIgnoreCase); return(new AppendDefaultExtensionResult(true, href, isMarkdownFile)); } } else if (index == 0) { return(new AppendDefaultExtensionResult(true, href, false)); } else { var hrefWithoutAnchor = href.Remove(index).TrimEnd('/'); var anchor = href.Substring(index); var extension = Path.GetExtension(hrefWithoutAnchor); if (string.IsNullOrEmpty(extension)) { return(new AppendDefaultExtensionResult(true, $"{hrefWithoutAnchor}{defaultExtension}{anchor}", true)); } else { bool isMarkdownFile = extension.Equals(MarkdownExtension, StringComparison.OrdinalIgnoreCase); return(new AppendDefaultExtensionResult(true, $"{hrefWithoutAnchor}{anchor}", isMarkdownFile)); } } }
public virtual StringBuffer Render(IMarkdownRenderer renderer, DfmFencesToken token, IMarkdownContext context) { if (!TypeForwardedToPathUtility.IsRelativePath(token.Path)) { string errorMessage = $"Code absolute path: {token.Path} is not supported in file {context.GetFilePathStack().Peek()}"; Logger.LogError(errorMessage); return(DfmFencesBlockHelper.GetRenderedFencesBlockString(token, renderer.Options, errorMessage)); } try { // Always report original dependency context.ReportDependency(token.Path); var filePathWithStatus = DfmFallbackHelper.GetFilePathWithFallback(token.Path, context); var extractResult = _dfmCodeExtractor.ExtractFencesCode(token, filePathWithStatus.Item1); var result = DfmFencesBlockHelper.GetRenderedFencesBlockString(token, renderer.Options, extractResult.ErrorMessage, extractResult.FencesCodeLines); return(result); } catch (DirectoryNotFoundException) { return(DfmFencesBlockHelper.GenerateReferenceNotFoundErrorMessage(renderer, token)); } catch (FileNotFoundException) { return(DfmFencesBlockHelper.GenerateReferenceNotFoundErrorMessage(renderer, token)); } }
public string ResolveSourceRelativePath(string originPath, string currentFileOutputPath) { if (string.IsNullOrEmpty(originPath) || !TypeForwardedToPathUtility.IsRelativePath(originPath)) { return(originPath); } var origin = (TypeForwardedToRelativePath)originPath; if (origin == null) { return(originPath); } var destPath = _context.GetFilePath(origin.GetPathFromWorkingFolder().ToString()); if (destPath != null) { return(((TypeForwardedToRelativePath)destPath - ((TypeForwardedToRelativePath)currentFileOutputPath).GetPathFromWorkingFolder()).ToString()); } else { Logger.LogWarning($"Can't find output file for {originPath}"); return(originPath); } }
public static HrefType GetHrefType(string href) { if (!TypeForwardedToPathUtility.IsRelativePath(href)) { return(HrefType.AbsolutePath); } var fileName = Path.GetFileName(href); if (string.IsNullOrEmpty(fileName)) { return(HrefType.RelativeFolder); } var tocFileType = GetTocFileType(href); if (tocFileType == TocFileType.Markdown) { return(HrefType.MarkdownTocFile); } if (tocFileType == TocFileType.Yaml) { return(HrefType.YamlTocFile); } return(HrefType.RelativeFile); }
private string LoadCore(IMarkdownRenderer adapter, string currentPath, string raw, SourceInfo sourceInfo, IMarkdownContext context, DfmEngine engine) { try { if (!TypeForwardedToPathUtility.IsRelativePath(currentPath)) { return(GenerateErrorNodeWithCommentWrapper("INCLUDE", $"Absolute path \"{currentPath}\" is not supported.", raw, sourceInfo)); } // Always report original include file dependency var originalRelativePath = currentPath; context.ReportDependency(currentPath); var parents = context.GetFilePathStack(); string parent = string.Empty; if (parents == null) { parents = ImmutableStack <string> .Empty; } // Update currentPath to be referencing to sourcePath else if (!parents.IsEmpty) { parent = parents.Peek(); currentPath = ((TypeForwardedToRelativePath)currentPath).BasedOn((TypeForwardedToRelativePath)parent); } if (parents.Contains(currentPath, TypeForwardedToFilePathComparer.OSPlatformSensitiveComparer)) { return(GenerateErrorNodeWithCommentWrapper("INCLUDE", $"Unable to resolve {raw}: Circular dependency found in \"{parent}\"", raw, sourceInfo)); } // Add current file path to chain when entering recursion parents = parents.Push(currentPath); string result; HashSet <string> dependency; if (!_dependencyCache.TryGetValue(currentPath, out dependency) || !_cache.TryGet(currentPath, out result)) { var filePathWithStatus = DfmFallbackHelper.GetFilePathWithFallback(originalRelativePath, context); var src = File.ReadAllText(filePathWithStatus.Item1); dependency = new HashSet <string>(); src = engine.InternalMarkup(src, context.SetFilePathStack(parents).SetDependency(dependency).SetIsInclude()); result = UpdateToHrefFromWorkingFolder(src, currentPath); result = GenerateNodeWithCommentWrapper("INCLUDE", $"Include content from \"{currentPath}\"", result); _cache.Add(currentPath, result); _dependencyCache[currentPath] = dependency; } context.ReportDependency( from d in dependency select(string)((TypeForwardedToRelativePath)currentPath + (TypeForwardedToRelativePath)d - (TypeForwardedToRelativePath)parent)); return(result); } catch (Exception e) { return(GenerateErrorNodeWithCommentWrapper("INCLUDE", $"Unable to resolve {raw}:{e.Message}", raw, sourceInfo)); } }
private static void UpdateToHrefFromWorkingFolder(HtmlNode html, string filePath) { foreach (var pair in GetHrefNodes(html)) { var link = pair.Attr; if (TypeForwardedToPathUtility.IsRelativePath(link.Value) && !TypeForwardedToRelativePath.IsPathFromWorkingFolder(link.Value) && !link.Value.StartsWith("#")) { link.Value = ((TypeForwardedToRelativePath)filePath + (TypeForwardedToRelativePath)link.Value).GetPathFromWorkingFolder(); } } }
/// <summary> /// Append default extension to href by condition /// </summary> /// <param name="href">original href string</param> /// <param name="defaultExtension">default extension to append</param> /// <param name="isHrefRelativeNonMdFile">true if it is a relative path and not a markdown file. Otherwise false</param> /// <returns>Href with default extension appended</returns> private string AppendDefaultExtension(string href, string defaultExtension, out bool isHrefRelativeNonMdFile) { isHrefRelativeNonMdFile = false; if (!TypeForwardedToPathUtility.IsRelativePath(href)) { return(href); } var index = href.IndexOf('#'); if (index == -1) { href = href.TrimEnd('/'); var extension = Path.GetExtension(href); // Regard all the relative path with no extension as markdown file that missing .md if (string.IsNullOrEmpty(extension)) { return($"{href}{defaultExtension}"); } else { if (!extension.Equals(MarkdownExtension, StringComparison.OrdinalIgnoreCase)) { isHrefRelativeNonMdFile = true; } return(href); } } else if (index == 0) { return(href); } else { var hrefWithoutAnchor = href.Remove(index).TrimEnd('/'); var anchor = href.Substring(index); var extension = Path.GetExtension(hrefWithoutAnchor); if (string.IsNullOrEmpty(extension)) { return($"{hrefWithoutAnchor}{defaultExtension}{anchor}"); } else { if (!extension.Equals(MarkdownExtension, StringComparison.OrdinalIgnoreCase)) { isHrefRelativeNonMdFile = true; } return($"{hrefWithoutAnchor}{anchor}"); } } }
public void Add(string filePath, ChangeKind kind) { if (filePath == null) { throw new ArgumentNullException(nameof(filePath)); } if (filePath.Length == 0) { throw new ArgumentException("File path cannot be empty", nameof(filePath)); } if (!TypeForwardedToPathUtility.IsRelativePath(filePath)) { throw new ArgumentException("Expect relative path.", nameof(filePath)); } AddCore(filePath, kind); }
// TODO: use this method instead of directly accessing UidMap public void RegisterInternalXrefSpec(XRefSpec xrefSpec) { if (xrefSpec == null) { throw new ArgumentNullException(nameof(xrefSpec)); } if (string.IsNullOrEmpty(xrefSpec.Href)) { throw new ArgumentException("Href for xref spec must contain value"); } if (!TypeForwardedToPathUtility.IsRelativePath(xrefSpec.Href)) { throw new ArgumentException("Only relative href path is supported"); } XRefSpecMap[xrefSpec.Uid] = xrefSpec; }
public IMarkdownToken TryMatch(IMarkdownParser engine, IMarkdownParsingContext context) { var match = AzureIncludeRegex.Match(context.CurrentMarkdown); if (match.Length == 0) { return(null); } var sourceInfo = context.Consume(match.Length); // [!azure.include[title](path "optionalTitle")] // 1. Get include file path var path = match.Groups[2].Value; // 2. Get title var value = match.Groups[1].Value; var title = match.Groups[4].Value; if (!TypeForwardedToPathUtility.IsRelativePath(path)) { Logger.LogWarning($"Azure inline include path {path} is not a relative path, can't expand it"); return(new MarkdownTextToken(this, engine.Context, match.Value, sourceInfo)); } // 3. Apply inline rules to the included content object currentFilePath; if (!engine.Context.Variables.TryGetValue("path", out currentFilePath)) { Logger.LogWarning($"Can't get path for the file that ref azure inline include file, return MarkdownTextToken. Raw: {match.Value}"); return(new MarkdownTextToken(this, engine.Context, match.Value, sourceInfo)); } var includeFilePath = TypeForwardedToPathUtility.NormalizePath(Path.Combine(Path.GetDirectoryName(currentFilePath.ToString()), path)); if (!File.Exists(includeFilePath)) { Logger.LogWarning($"Can't get include file path {includeFilePath} in the file {currentFilePath}, return MarkdownTextToken. Raw: {match.Value}"); return(new MarkdownTextToken(this, engine.Context, match.Value, sourceInfo)); } return(new TwoPhaseBlockToken(this, engine.Context, sourceInfo, (p, t) => { var inlineTokens = p.Tokenize(SourceInfo.Create(MarkdownEngine.Normalize(File.ReadAllText(includeFilePath)), includeFilePath)); return new AzureIncludeInlineToken(t.Rule, t.Context, path, value, title, inlineTokens, match.Groups[0].Value, t.SourceInfo); })); }
private string CheckNonMdRelativeFileHref(string nonMdHref, IMarkdownContext context, string rawMarkdown, string line) { // If the context doesn't have necessary info or nonMdHref is not a relative path, return the original href if (!context.Variables.ContainsKey("path") || !TypeForwardedToPathUtility.IsRelativePath(nonMdHref)) { return(nonMdHref); } var currentFilePath = (string)context.Variables["path"]; var currentFolderPath = Path.GetDirectoryName(currentFilePath); var nonMdExpectedPath = Path.Combine(currentFolderPath, nonMdHref); if (!File.Exists(nonMdExpectedPath)) { Logger.LogWarning($"Can't find resource reference: {nonMdHref}. Raw: {rawMarkdown}.", null, currentFilePath, line); } return(nonMdHref); }
public override void UpdateHref(FileModel model, IDocumentBuildContext context) { var toc = (TocItemViewModel)model.Content; var key = model.Key; // Add current folder to the toc mapping, e.g. `a/` maps to `a/toc` var directory = ((TypeForwardedToRelativePath)key).GetPathFromWorkingFolder().GetDirectoryPath(); context.RegisterToc(key, directory); UpdateTocItemHref(toc, model, context); var tocInfo = new TocInfo(key); if (toc.Homepage != null) { if (TypeForwardedToPathUtility.IsRelativePath(toc.Homepage)) { var pathToRoot = ((TypeForwardedToRelativePath)model.File + (TypeForwardedToRelativePath)toc.Homepage).GetPathFromWorkingFolder(); tocInfo.Homepage = pathToRoot; } } context.RegisterTocInfo(tocInfo); }
private static void MergeOptionsToConfig(BuildCommandOptions options, BuildJsonConfig config) { // base directory for content from command line is current directory // e.g. C:\folder1>docfx build folder2\docfx.json --content "*.cs" // for `--content "*.cs*`, base directory should be `C:\folder1` string optionsBaseDirectory = Directory.GetCurrentDirectory(); config.OutputFolder = options.OutputFolder; // Override config file with options from command line if (options.Templates != null && options.Templates.Count > 0) { config.Templates = new ListWithStringFallback(options.Templates); } if (options.PostProcessors != null && options.PostProcessors.Count > 0) { config.PostProcessors = new ListWithStringFallback(options.PostProcessors); } if (options.Themes != null && options.Themes.Count > 0) { config.Themes = new ListWithStringFallback(options.Themes); } if (!string.IsNullOrEmpty(options.OutputFolder)) { config.Destination = Path.GetFullPath(Path.Combine(options.OutputFolder, config.Destination ?? string.Empty)); } if (options.Content != null) { if (config.Content == null) { config.Content = new FileMapping(new FileMappingItem()); } config.Content.Add( new FileMappingItem { Files = new FileItems(options.Content), SourceFolder = optionsBaseDirectory, }); } if (options.Resource != null) { if (config.Resource == null) { config.Resource = new FileMapping(new FileMappingItem()); } config.Resource.Add( new FileMappingItem { Files = new FileItems(options.Resource), SourceFolder = optionsBaseDirectory, }); } if (options.Overwrite != null) { if (config.Overwrite == null) { config.Overwrite = new FileMapping(new FileMappingItem()); } config.Overwrite.Add( new FileMappingItem { Files = new FileItems(options.Overwrite), SourceFolder = optionsBaseDirectory, }); } if (options.ExternalReference != null) { if (config.ExternalReference == null) { config.ExternalReference = new FileMapping(new FileMappingItem()); } config.ExternalReference.Add( new FileMappingItem { Files = new FileItems(options.ExternalReference), SourceFolder = optionsBaseDirectory, }); } if (options.XRefMaps != null) { config.XRefMaps = new ListWithStringFallback( (config.XRefMaps ?? new ListWithStringFallback()) .Concat(options.XRefMaps) .Where(x => !string.IsNullOrWhiteSpace(x)) .Distinct()); } //to-do: get changelist from options if (options.Serve) { config.Serve = options.Serve; } if (options.Port.HasValue) { config.Port = options.Port.Value.ToString(); } config.Force |= options.ForceRebuild; config.ExportRawModel |= options.ExportRawModel; config.ExportViewModel |= options.ExportViewModel; if (!string.IsNullOrEmpty(options.RawModelOutputFolder)) { config.RawModelOutputFolder = Path.GetFullPath(options.RawModelOutputFolder); } if (!string.IsNullOrEmpty(options.ViewModelOutputFolder)) { config.ViewModelOutputFolder = Path.GetFullPath(options.ViewModelOutputFolder); } config.DryRun |= options.DryRun; if (options.MaxParallelism != null) { config.MaxParallelism = options.MaxParallelism; } if (options.MarkdownEngineName != null) { config.MarkdownEngineName = options.MarkdownEngineName; } if (options.MarkdownEngineProperties != null) { config.MarkdownEngineProperties = JsonConvert.DeserializeObject <Dictionary <string, object> >( options.MarkdownEngineProperties, new JsonSerializerSettings { Converters = { new JObjectDictionaryToObjectDictionaryConverter() } }); } if (options.NoLangKeyword != null) { config.NoLangKeyword = options.NoLangKeyword.Value; } if (options.IntermediateFolder != null) { config.IntermediateFolder = options.IntermediateFolder; } if (options.ChangesFile != null) { config.ChangesFile = options.ChangesFile; } if (options.GlobalMetadataFilePaths != null && options.GlobalMetadataFilePaths.Any()) { config.GlobalMetadataFilePaths.AddRange(options.GlobalMetadataFilePaths); } config.GlobalMetadataFilePaths = new ListWithStringFallback(config.GlobalMetadataFilePaths.Select( path => TypeForwardedToPathUtility.IsRelativePath(path) ? Path.Combine(config.BaseDirectory, path) : path).Reverse()); if (options.FileMetadataFilePaths != null && options.FileMetadataFilePaths.Any()) { config.FileMetadataFilePaths.AddRange(options.FileMetadataFilePaths); } config.FileMetadataFilePaths = new ListWithStringFallback(config.FileMetadataFilePaths.Select( path => TypeForwardedToPathUtility.IsRelativePath(path) ? Path.Combine(config.BaseDirectory, path) : path).Reverse()); config.FileMetadata = GetFileMetadataFromOption(config.FileMetadata, options.FileMetadataFilePath, config.FileMetadataFilePaths); config.GlobalMetadata = GetGlobalMetadataFromOption(config.GlobalMetadata, options.GlobalMetadataFilePath, config.GlobalMetadataFilePaths, options.GlobalMetadata); }
private string GenerateAzureLinkHref(IMarkdownContext context, string href, string rawMarkdown, string line) { if (string.IsNullOrEmpty(href)) { return(string.Empty); } StringBuffer content = StringBuffer.Empty; // If the context doesn't have necessary info, return the original href if (!context.Variables.ContainsKey("path") || !context.Variables.ContainsKey("azureMarkdownFileInfoMapping")) { return(href); } // if the href is not relative path, return it. Add try catch to keep this method safe. try { if (!TypeForwardedToPathUtility.IsRelativePath(href)) { return(href); } } catch (ArgumentException) { Logger.LogWarning($"Invalid reference {href} in file: {(string)context.Variables["path"]}. Raw: {rawMarkdown}", null, (string)context.Variables["path"], line); return(href); } // deal with bookmark. Get file name and anchor string hrefFileName = string.Empty; string anchor = string.Empty; var index = href.IndexOf('#'); if (index == -1) { hrefFileName = Path.GetFileName(href); } else if (index == 0) { return(href); } else { hrefFileName = Path.GetFileName(href.Remove(index)); anchor = href.Substring(index); } // deal with different kinds of relative paths var currentFilePath = (string)context.Variables["path"]; var azureMarkdownFileInfoMapping = (IReadOnlyDictionary <string, AzureFileInfo>)context.Variables["azureMarkdownFileInfoMapping"]; if (azureMarkdownFileInfoMapping == null || !azureMarkdownFileInfoMapping.ContainsKey(hrefFileName)) { Logger.LogWarning($"Can't find markdown reference: {href}. Raw: {rawMarkdown}.", null, currentFilePath, line); return(href); } string azureHref = null; var hrefFileInfo = azureMarkdownFileInfoMapping[hrefFileName]; azureHref = string.Format("{0}{1}", TypeForwardedToPathUtility.MakeRelativePath(Path.GetDirectoryName(currentFilePath), hrefFileInfo.FilePath), anchor); return(azureHref); }
private string FixNonMdRelativeFileHref(string nonMdHref, IMarkdownContext context, string rawMarkdown) { // If the context doesn't have necessary info or nonMdHref is not a relative path, return the original href if (!context.Variables.ContainsKey("path") || !TypeForwardedToPathUtility.IsRelativePath(nonMdHref)) { return(nonMdHref); } var currentFilePath = (string)context.Variables["path"]; var currentFolderPath = Path.GetDirectoryName(currentFilePath); try { // if the relative path (not from azure resource file info mapping) is under docset. Just return it. var nonMdHrefFullPath = Path.GetFullPath(Path.Combine(currentFolderPath, nonMdHref)); if (TypeForwardedToPathUtility.IsPathUnderSpecificFolder(nonMdHrefFullPath, currentFolderPath)) { return(nonMdHref); } else { Logger.LogVerbose($"Relative path:{nonMdHref} is not under {currentFolderPath} of file {currentFilePath}. Use ex_resource to replace the link."); } // if azure resource file info doesn't exist, log warning and return if (!context.Variables.ContainsKey("azureResourceFileInfoMapping")) { Logger.LogWarning($"Can't find azure resource file info mapping. Couldn't fix href: {nonMdHref} in file {currentFilePath}. raw: {rawMarkdown}"); return(nonMdHref); } var nonMdHrefFileName = Path.GetFileName(nonMdHref); var azureResourceFileInfoMapping = (Dictionary <string, AzureFileInfo>)context.Variables["azureResourceFileInfoMapping"]; AzureFileInfo azureResourceFileInfo; if (!azureResourceFileInfoMapping.TryGetValue(nonMdHrefFileName, out azureResourceFileInfo)) { Logger.LogWarning($"Can't find info for file name {nonMdHrefFileName} in azure resource file info mapping. Couldn't fix href: {nonMdHref} in file {currentFilePath}. raw: {rawMarkdown}"); return(nonMdHref); } // If the nonMdHref is under same docset with current file. No need to fix that. if (TypeForwardedToPathUtility.IsPathUnderSpecificFolder(azureResourceFileInfo.FilePath, currentFolderPath)) { return(nonMdHref); } // If the nonMdHref is under different docset with current file but not exists. Then log warning and won't fix. if (!File.Exists(azureResourceFileInfo.FilePath)) { Logger.LogWarning($"{nonMdHref} refer by {currentFilePath} doesn't exists. Won't do link fix. raw: {rawMarkdown}"); return(nonMdHref); } // If the nonMdHref is under different docset with current file and also exists, then fix the link. // 1. copy the external file to ex_resource folder. 2. Return new href path to the file under external folder var exResourceDir = Directory.CreateDirectory(Path.Combine(currentFolderPath, ExternalResourceFolderName)); var resDestPath = Path.Combine(exResourceDir.FullName, Path.GetFileName(azureResourceFileInfo.FilePath)); File.Copy(azureResourceFileInfo.FilePath, resDestPath, true); return(TypeForwardedToPathUtility.MakeRelativePath(currentFolderPath, resDestPath)); } catch (NotSupportedException nse) { Logger.LogWarning($"Warning: FixNonMdRelativeFileHref can't be apply on reference: {nonMdHref}. Exception: {nse.Message}"); return(nonMdHref); } }
private string GenerateAzureLinkHref(IMarkdownContext context, string href, string rawMarkdown) { StringBuffer content = StringBuffer.Empty; // If the context doesn't have necessary info, return the original href if (!context.Variables.ContainsKey("path") || !context.Variables.ContainsKey("azureMarkdownFileInfoMapping")) { return(href); } // if the href is not relative path, return it if (!TypeForwardedToPathUtility.IsRelativePath(href)) { return(href); } // deal with bookmark. Get file name and anchor string hrefFileName = string.Empty; string anchor = string.Empty; var index = href.IndexOf('#'); if (index == -1) { hrefFileName = Path.GetFileName(href); } else if (index == 0) { return(href); } else { hrefFileName = Path.GetFileName(href.Remove(index)); anchor = href.Substring(index); } // deal with different kinds of relative paths var currentFilePath = (string)context.Variables["path"]; var azureMarkdownFileInfoMapping = (IReadOnlyDictionary <string, AzureFileInfo>)context.Variables["azureMarkdownFileInfoMapping"]; if (azureMarkdownFileInfoMapping == null || !azureMarkdownFileInfoMapping.ContainsKey(hrefFileName)) { Logger.LogWarning($"Can't fild reference file: {href} in azure file system for file {currentFilePath}. Raw: {rawMarkdown}"); return(href); } string azureHref = null; var hrefFileInfo = azureMarkdownFileInfoMapping[hrefFileName]; // Not in docsets and transform to azure external link if (hrefFileInfo.NeedTransformToAzureExternalLink) { azureHref = $"{hrefFileInfo.UriPrefix}/{Path.GetFileNameWithoutExtension(hrefFileName)}{anchor}"; } else { var hrefPath = hrefFileInfo.FilePath; // It is correct for Azure strucuture. Azure articles are all under same folder var isHrefInsameDocset = TypeForwardedToPathUtility.IsPathUnderSpecificFolder(hrefPath, Path.GetDirectoryName(currentFilePath)); // In same docset with current file, use relative path. Otherwise, use docset link prefix if (isHrefInsameDocset) { azureHref = string.Format("{0}{1}", TypeForwardedToPathUtility.MakeRelativePath(Path.GetDirectoryName(currentFilePath), hrefFileInfo.FilePath), anchor); } else { // If the file is in different docset, then append the absolute path prefix. .html should be remove as docs also don't need it now. azureHref = $"{hrefFileInfo.UriPrefix}/{Path.GetFileNameWithoutExtension(hrefFileName)}{anchor}"; } } return(azureHref); }
public override void Handle(HtmlDocument document, ManifestItem manifestItem, string inputFile, string outputFile) { _fileMapping[outputFile] = inputFile; // RFC 3986: relative-ref = relative-part [ "?" query ] [ "#" fragment ] _linksWithBookmark[outputFile] = (from node in GetNodesWithAttribute(document, "href") let link = node.GetAttributeValue("href", null) let bookmarkIndex = link.IndexOf("#") where bookmarkIndex != -1 let bookmark = link.Substring(bookmarkIndex + 1) let index = link.IndexOfAny(new[] { '?', '#' }) let decodedLink = HttpUtility.UrlDecode(link.Remove(index)) where !WhiteList.Contains(bookmark) && TypeForwardedToPathUtility.IsRelativePath(decodedLink) select new LinkItem { Title = node.InnerText, Href = TransformPath(outputFile, decodedLink), Bookmark = bookmark, SourceFragment = WebUtility.HtmlDecode(node.GetAttributeValue("data-raw-source", null)), SourceFile = WebUtility.HtmlDecode(node.GetAttributeValue("sourceFile", null)), SourceLineNumber = node.GetAttributeValue("sourceStartLineNumber", 0), TargetLineNumber = node.Line }).ToList(); var anchors = GetNodeAttribute(document, "id").Concat(GetNodeAttribute(document, "name")); _registeredBookmarks[outputFile] = new HashSet <string>(anchors); }