예제 #1
0
        private IEnumerable <string> GetFiles(string directory, string searchPattern, int searchLevel)
        {
            if (searchLevel < 1)
            {
                return(Enumerable.Empty <string>());
            }
            var files = Directory.GetFiles(directory, searchPattern, SearchOption.TopDirectoryOnly);
            var dirs  = Directory.GetDirectories(directory);

            if (searchLevel == 1)
            {
                foreach (var dir in dirs)
                {
                    var remainingFiles = Directory.GetFiles(dir, searchPattern, SearchOption.AllDirectories);

                    if (remainingFiles.Length > 0)
                    {
                        throw new ResourceFileExceedsMaxDepthException(_maxDepth, TypeForwardedToPathUtility.MakeRelativePath(_directory, remainingFiles[0]), Name);
                    }
                }
                return(files);
            }
            List <string> allFiles = new List <string>(files);

            foreach (var dir in dirs)
            {
                allFiles.AddRange(GetFiles(dir, searchPattern, searchLevel - 1));
            }
            return(allFiles);
        }
예제 #2
0
        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);
        }
예제 #3
0
        private static ImmutableDictionary <string, object> ApplyFileMetadata(
            string file,
            ImmutableDictionary <string, object> metadata,
            FileMetadata fileMetadata)
        {
            if (fileMetadata == null || fileMetadata.Count == 0)
            {
                return(metadata);
            }
            var result  = new Dictionary <string, object>(metadata);
            var baseDir = string.IsNullOrEmpty(fileMetadata.BaseDir) ? Directory.GetCurrentDirectory() : fileMetadata.BaseDir;
            var TypeForwardedToRelativePath = TypeForwardedToPathUtility.MakeRelativePath(baseDir, file);

            foreach (var item in fileMetadata)
            {
                // As the latter one overrides the former one, match the pattern from latter to former
                for (int i = item.Value.Length - 1; i >= 0; i--)
                {
                    if (item.Value[i].Glob.Match(TypeForwardedToRelativePath))
                    {
                        // override global metadata if metadata is defined in file metadata
                        result[item.Value[i].Key] = item.Value[i].Value;
                        Logger.LogVerbose($"{TypeForwardedToRelativePath} matches file metadata with glob pattern {item.Value[i].Glob.Raw} for property {item.Value[i].Key}");
                        break;
                    }
                }
            }
            return(result.ToImmutableDictionary());
        }
예제 #4
0
        public override FileModel Load(FileAndType file, ImmutableDictionary <string, object> metadata)
        {
            if (file.Type != DocumentType.Article)
            {
                throw new NotSupportedException();
            }
            var content = MarkdownReader.ReadMarkdownAsConceptual(file.BaseDir, file.File);

            foreach (var item in metadata)
            {
                if (!content.ContainsKey(item.Key))
                {
                    content[item.Key] = item.Value;
                }
            }

            var displayLocalPath = TypeForwardedToPathUtility.MakeRelativePath(EnvironmentContext.BaseDirectory, file.FullPath);

            return(new FileModel(
                       file,
                       content,
                       serializer: Environment.Is64BitProcess?null: new BinaryFormatter())
            {
                LocalPathFromRepoRoot = (content["source"] as SourceDetail)?.Remote?.RelativePath,
                LocalPathFromRoot = displayLocalPath
            });
        }
예제 #5
0
        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,
            });
        }
예제 #6
0
파일: DfmRenderer.cs 프로젝트: runt18/docfx
        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));
            }
        }
예제 #7
0
        /// <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));
                }
            }
        }
예제 #8
0
파일: HostService.cs 프로젝트: runt18/docfx
        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()));
        }
예제 #9
0
        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);
            }
        }
예제 #10
0
        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);
        }
예제 #11
0
        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));
            }
        }
예제 #12
0
 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();
         }
     }
 }
예제 #13
0
        /// <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}");
                }
            }
        }
예제 #14
0
        private static void CopyFromCachedResult(BuildInfo buildInfo, IEnumerable <string> inputs, string outputFolder)
        {
            var outputFolderSource = buildInfo.OutputFolder;
            var relativeFiles      = buildInfo.RelatvieOutputFiles;

            if (relativeFiles == null)
            {
                Logger.Log(LogLevel.Warning, $"No metadata is generated for '{TypeForwardedToStringExtension.ToDelimitedString(inputs)}'.");
                return;
            }

            Logger.Log(LogLevel.Info, $"'{TypeForwardedToStringExtension.ToDelimitedString(inputs)}' keep up-to-date since '{buildInfo.TriggeredUtcTime.ToString()}', cached result from '{buildInfo.OutputFolder}' is used.");
            TypeForwardedToPathUtility.CopyFilesToFolder(relativeFiles.Select(s => Path.Combine(outputFolderSource, s)), outputFolderSource, outputFolder, true, s => Logger.Log(LogLevel.Info, s), null);
        }
예제 #15
0
 // 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;
 }
예제 #16
0
 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);
 }
예제 #17
0
        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);
            }));
        }
예제 #18
0
        public FileResourceCollection(string directory, int maxSearchLevel = MaxSearchLevel)
        {
            if (string.IsNullOrEmpty(directory))
            {
                _directory = Directory.GetCurrentDirectory();
            }
            else
            {
                _directory = directory;
            }
            Name      = _directory;
            _maxDepth = maxSearchLevel;
            var includedFiles = GetFiles(_directory, "*", maxSearchLevel);

            Names = includedFiles.Select(s => TypeForwardedToPathUtility.MakeRelativePath(_directory, s)).Where(s => s != null);

            IsEmpty = !Names.Any();
        }
예제 #19
0
        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);
        }
예제 #20
0
        public override FileModel Load(FileAndType file, ImmutableDictionary <string, object> metadata)
        {
            switch (file.Type)
            {
            case DocumentType.Article:
                var filePath       = Path.Combine(file.BaseDir, file.File);
                var swaggerContent = File.ReadAllText(filePath);
                var swagger        = SwaggerJsonParser.Parse(swaggerContent);
                swagger.Metadata[DocumentTypeKey] = RestApiDocumentType;
                swagger.Raw = swaggerContent;
                CheckOperationId(swagger, file.File);

                var repoInfo = GitUtility.GetGitDetail(filePath);
                if (repoInfo != null)
                {
                    swagger.Metadata["source"] = new SourceDetail()
                    {
                        Remote = repoInfo
                    };
                }

                swagger.Metadata = MergeMetadata(swagger.Metadata, metadata);
                var vm = SwaggerModelConverter.FromSwaggerModel(swagger);
                var displayLocalPath = TypeForwardedToPathUtility.MakeRelativePath(EnvironmentContext.BaseDirectory, file.FullPath);

                return(new FileModel(file, vm, serializer: Environment.Is64BitProcess?null: new BinaryFormatter())
                {
                    Uids = new[] { new UidDefinition(vm.Uid, displayLocalPath) }
                    .Concat(from item in vm.Children select new UidDefinition(item.Uid, displayLocalPath))
                    .Concat(from tag in vm.Tags select new UidDefinition(tag.Uid, displayLocalPath)).ToImmutableArray(),
                    LocalPathFromRepoRoot = repoInfo?.RelativePath ?? TypeForwardedToStringExtension.ToDisplayPath(filePath),
                    LocalPathFromRoot = displayLocalPath
                });

            case DocumentType.Overwrite:
                // TODO: Refactor current behavior that overwrite file is read multiple times by multiple processors
                return(OverwriteDocumentReader.Read(file));

            default:
                throw new NotSupportedException();
            }
        }
예제 #21
0
        public override FileModel Load(FileAndType file, ImmutableDictionary <string, object> metadata)
        {
            switch (file.Type)
            {
            case DocumentType.Article:
                var page = YamlUtility.Deserialize <PageViewModel>(Path.Combine(file.BaseDir, file.File));
                if (page.Items == null || page.Items.Count == 0)
                {
                    return(null);
                }
                if (page.Metadata == null)
                {
                    page.Metadata = metadata.ToDictionary(p => p.Key, p => p.Value);
                }
                else
                {
                    foreach (var item in metadata)
                    {
                        if (!page.Metadata.ContainsKey(item.Key))
                        {
                            page.Metadata[item.Key] = item.Value;
                        }
                    }
                }

                var displayLocalPath = TypeForwardedToPathUtility.MakeRelativePath(EnvironmentContext.BaseDirectory, file.FullPath);

                return(new FileModel(file, page, serializer: Environment.Is64BitProcess?null: new BinaryFormatter())
                {
                    Uids = (from item in page.Items select new UidDefinition(item.Uid, displayLocalPath)).ToImmutableArray(),
                    LocalPathFromRepoRoot = displayLocalPath,
                    LocalPathFromRoot = displayLocalPath
                });

            case DocumentType.Overwrite:
                // TODO: Refactor current behavior that overwrite file is read multiple times by multiple processors
                return(OverwriteDocumentReader.Read(file));

            default:
                throw new NotSupportedException();
            }
        }
예제 #22
0
        public override FileModel Load(FileAndType file, ImmutableDictionary <string, object> metadata)
        {
            var filePath     = file.FullPath;
            var tocViewModel = Utility.LoadSingleToc(filePath);
            var toc          = new TocItemViewModel
            {
                Items = tocViewModel
            };

            var repoDetail       = GitUtility.GetGitDetail(filePath);
            var displayLocalPath = TypeForwardedToPathUtility.MakeRelativePath(EnvironmentContext.BaseDirectory, file.FullPath);

            // todo : metadata.
            return(new FileModel(file, toc)
            {
                Uids = new[] { new UidDefinition(file.File, displayLocalPath) }.ToImmutableArray(),
                LocalPathFromRepoRoot = repoDetail?.RelativePath ?? filePath,
                LocalPathFromRoot = displayLocalPath
            });
        }
예제 #23
0
        public static SourceDetail GetSourceDetail(ISymbol symbol)
        {
            // For namespace, definition is meaningless
            if (symbol == null || symbol.Kind == SymbolKind.Namespace)
            {
                return(null);
            }

            var syntaxRef = symbol.DeclaringSyntaxReferences.LastOrDefault();

            if (symbol.IsExtern || syntaxRef == null)
            {
                return(new SourceDetail
                {
                    IsExternalPath = true,
                    Path = symbol.ContainingAssembly?.Name,
                });
            }

            var syntaxNode = syntaxRef.GetSyntax();

            Debug.Assert(syntaxNode != null);
            if (syntaxNode != null)
            {
                var source = new SourceDetail
                {
                    StartLine = syntaxNode.SyntaxTree.GetLineSpan(syntaxNode.Span).StartLinePosition.Line,
                    Path      = syntaxNode.SyntaxTree.FilePath,
                    Name      = symbol.Name
                };

                source.Remote = GitUtility.GetGitDetail(source.Path);
                if (source.Remote != null)
                {
                    source.Path = TypeForwardedToPathUtility.FormatPath(source.Path, UriKind.Relative, source.Remote.LocalWorkingDirectory);
                }
                return(source);
            }

            return(null);
        }
예제 #24
0
        public override FileModel Load(FileAndType file, ImmutableDictionary <string, object> metadata)
        {
            string uid = null;
            Dictionary <string, object> content = null;
            var metafile = Path.Combine(file.BaseDir, file.File.TrimEnd('.') + ".meta");

            if (File.Exists(metafile))
            {
                content = YamlUtility.Deserialize <Dictionary <string, object> >(metafile);
                if (content != null)
                {
                    foreach (var item in metadata)
                    {
                        if (!content.ContainsKey(item.Key))
                        {
                            content[item.Key] = item.Value;
                        }
                        if (item.Key == Constants.PropertyName.Uid)
                        {
                            uid = item.Value as string;
                        }
                    }
                }
            }
            if (content == null)
            {
                content = metadata.ToDictionary(p => p.Key, p => p.Value);
            }

            var filePath         = Path.Combine(file.BaseDir, file.File);
            var repoDetail       = GitUtility.GetGitDetail(filePath);
            var displayLocalPath = TypeForwardedToPathUtility.MakeRelativePath(EnvironmentContext.BaseDirectory, file.FullPath);

            return(new FileModel(file, content)
            {
                Uids = string.IsNullOrEmpty(uid) ? ImmutableArray <UidDefinition> .Empty : ImmutableArray <UidDefinition> .Empty.Add(new UidDefinition(uid, displayLocalPath)),
                LocalPathFromRepoRoot = repoDetail?.RelativePath ?? TypeForwardedToStringExtension.ToDisplayPath(Path.Combine(file.BaseDir, file.File)),
                LocalPathFromRoot = displayLocalPath
            });
        }
예제 #25
0
        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);
        }
예제 #26
0
        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);
        }
예제 #27
0
        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);
        }
예제 #28
0
        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);
            }
        }
예제 #29
0
        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);
        }
예제 #30
0
        public Manifest Process(Manifest manifest, string outputFolder)
        {
            if (outputFolder == null)
            {
                throw new ArgumentNullException("Base directory can not be null");
            }
            var indexData         = new Dictionary <string, SearchIndexItem>();
            var indexDataFilePath = Path.Combine(outputFolder, IndexFileName);
            var htmlFiles         = (from item in manifest.Files ?? Enumerable.Empty <ManifestItem>()
                                     from output in item.OutputFiles
                                     where output.Key.Equals(".html", StringComparison.OrdinalIgnoreCase)
                                     select output.Value.RelativePath).ToList();

            if (htmlFiles.Count == 0)
            {
                return(manifest);
            }

            Logger.LogInfo($"Extracting index data from {htmlFiles.Count} html files");
            foreach (var relativePath in htmlFiles)
            {
                var filePath = Path.Combine(outputFolder, relativePath);
                var html     = new HtmlDocument();
                Logger.LogVerbose($"Extracting index data from {filePath}");

                if (File.Exists(filePath))
                {
                    try
                    {
                        html.Load(filePath, Encoding.UTF8);
                    }
                    catch (Exception ex)
                    {
                        Logger.LogWarning($"Warning: Can't load content from {filePath}: {ex.Message}");
                        continue;
                    }
                    var indexItem = ExtractItem(html, relativePath);
                    if (indexItem != null)
                    {
                        indexData[relativePath] = indexItem;
                    }
                }
            }
            JsonUtility.Serialize(indexDataFilePath, indexData, Formatting.Indented);

            // add index.json to mainfest as resource file
            var manifestItem = new ManifestItem
            {
                DocumentType = "Resource",
                Metadata     = new Dictionary <string, object>(),
                OutputFiles  = new Dictionary <string, OutputFileInfo>()
            };

            manifestItem.OutputFiles.Add("resource", new OutputFileInfo
            {
                RelativePath = TypeForwardedToPathUtility.MakeRelativePath(outputFolder, indexDataFilePath),
            });

            manifest.Files?.Add(manifestItem);
            return(manifest);
        }