Ejemplo n.º 1
0
        private TocItemViewModel GetReferencedToc(FileAndType tocFile, Stack <FileAndType> stack)
        {
            if (_collection.TryGetValue(tocFile.FullPath, out TocItemInfo referencedTocFileModel) || _notInProjectTocCache.TryGetValue(tocFile, out referencedTocFileModel))
            {
                referencedTocFileModel = ResolveItem(referencedTocFileModel, stack);
                referencedTocFileModel.IsReferenceToc = true;
                return(referencedTocFileModel.Content);
            }
            else
            {
                // It is acceptable that the referenced toc file is not included in docfx.json, as long as it can be found locally
                TocItemViewModel referencedTocItemViewModel;
                try
                {
                    referencedTocItemViewModel = TocHelper.LoadSingleToc(tocFile.FullPath);
                }
                catch (FileNotFoundException)
                {
                    Logger.LogError($"Referenced TOC file {tocFile.FullPath} does not exist.", code: WarningCodes.Build.InvalidTocInclude);
                    return(null);
                }

                referencedTocFileModel = new TocItemInfo(tocFile, referencedTocItemViewModel);

                referencedTocFileModel         = ResolveItem(referencedTocFileModel, stack);
                _notInProjectTocCache[tocFile] = referencedTocFileModel;
                return(referencedTocFileModel.Content);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// 1. Expand the TOC reference
        /// 2. Resolve homepage
        /// </summary>
        public override IEnumerable <FileModel> Prebuild(ImmutableList <FileModel> models, IHostService host)
        {
            var(resolvedTocModels, includedTocs) = TocHelper.ResolveToc(models, host);

            ReportPreBuildDependency(resolvedTocModels, host, 8, includedTocs);

            return(resolvedTocModels);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// 1. Expand the TOC reference
        /// 2. Resolve homepage
        /// </summary>
        public override IEnumerable <FileModel> Prebuild(ImmutableList <FileModel> models, IHostService host)
        {
            var resolvedModels = TocHelper.Resolve(models, host).ToList();

            ReportPreBuildDependency(resolvedModels, host, 8);

            return(resolvedModels);
        }
Ejemplo n.º 4
0
        public override FileModel Load(FileAndType file, ImmutableDictionary <string, object> metadata)
        {
            var filePath = file.FullPath;
            var toc      = TocHelper.LoadSingleToc(filePath);

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

            // todo : metadata.
            return(new FileModel(file, toc)
            {
                Uids = new[] { new UidDefinition(file.File, displayLocalPath) }.ToImmutableArray(),
                LocalPathFromRoot = displayLocalPath
            });
        }
Ejemplo n.º 5
0
        private TocItemViewModel GetReferencedToc(FileAndType tocFile, Stack <FileAndType> stack)
        {
            if (_collection.TryGetValue(tocFile.FullPath, out TocItemInfo referencedTocFileModel) || _notInProjectTocCache.TryGetValue(tocFile, out referencedTocFileModel))
            {
                referencedTocFileModel = ResolveItem(referencedTocFileModel, stack);
                referencedTocFileModel.IsReferenceToc = true;
                return(referencedTocFileModel.Content);
            }
            else
            {
                // It is acceptable that the referenced toc file is not included in docfx.json, as long as it can be found locally
                referencedTocFileModel = new TocItemInfo(tocFile, TocHelper.LoadSingleToc(tocFile.FullPath));

                referencedTocFileModel         = ResolveItem(referencedTocFileModel, stack);
                _notInProjectTocCache[tocFile] = referencedTocFileModel;
                return(referencedTocFileModel.Content);
            }
        }
Ejemplo n.º 6
0
        public override FileModel Load(FileAndType file, ImmutableDictionary <string, object> metadata)
        {
            var filePath = file.FullPath;
            var toc      = TocHelper.LoadSingleToc(filePath);

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

            // Apply metadata to TOC
            foreach (var pair in metadata)
            {
                if (!toc.Metadata.TryGetValue(pair.Key, out var val))
                {
                    toc.Metadata[pair.Key] = pair.Value;
                }
            }

            return(new FileModel(file, toc)
            {
                LocalPathFromRoot = displayLocalPath
            });
        }
Ejemplo n.º 7
0
        private TocItemInfo ResolveItemCore(TocItemInfo wrapper, Stack <FileAndType> stack)
        {
            if (wrapper.IsResolved)
            {
                return(wrapper);
            }

            var file = wrapper.File;

            if (stack.Contains(file))
            {
                throw new DocumentException($"Circular reference to {file.FullPath} is found in {stack.Peek().FullPath}");
            }

            var item = wrapper.Content;

            // HomepageUid and Uid is deprecated, unified to TopicUid
            if (string.IsNullOrEmpty(item.TopicUid))
            {
                if (!string.IsNullOrEmpty(item.Uid))
                {
                    item.TopicUid = item.Uid;
                    item.Uid      = null;
                }
                else if (!string.IsNullOrEmpty(item.HomepageUid))
                {
                    item.TopicUid = item.HomepageUid;
                    Logger.LogWarning($"HomepageUid is deprecated in TOC. Please use topicUid to specify uid {item.Homepage}");
                    item.HomepageUid = null;
                }
            }
            // Homepage is deprecated, unified to TopicHref
            if (!string.IsNullOrEmpty(item.Homepage))
            {
                if (string.IsNullOrEmpty(item.TopicHref))
                {
                    item.TopicHref = item.Homepage;
                }
                else
                {
                    Logger.LogWarning($"Homepage is deprecated in TOC. Homepage {item.Homepage} is overwritten with topicHref {item.TopicHref}");
                }
            }
            // validate href
            ValidateHref(item);

            // TocHref supports 2 forms: absolute path and local toc file.
            // When TocHref is set, using TocHref as Href in output, and using Href as Homepage in output
            var tocHrefType = Utility.GetHrefType(item.TocHref);

            // check whether toc exists
            TocItemInfo tocFileModel = null;

            if (!string.IsNullOrEmpty(item.TocHref) && (tocHrefType == HrefType.MarkdownTocFile || tocHrefType == HrefType.YamlTocFile))
            {
                var tocFilePath = (RelativePath)file.File + (RelativePath)item.TocHref;
                var tocFile     = file.ChangeFile(tocFilePath);
                if (!_collection.TryGetValue(tocFile.FullPath, out tocFileModel))
                {
                    var message = $"Unable to find {item.TocHref}. Make sure the file is included in config file docfx.json!";
                    Logger.LogWarning(message);
                }
            }

            if (!string.IsNullOrEmpty(item.TocHref))
            {
                if (!string.IsNullOrEmpty(item.Homepage))
                {
                    throw new DocumentException(
                              $"TopicHref should be used to specify the homepage for {item.TocHref} when tocHref is used.");
                }
                if (tocHrefType == HrefType.RelativeFile || tocHrefType == HrefType.RelativeFolder)
                {
                    throw new DocumentException($"TocHref {item.TocHref} only supports absolute path or local toc file.");
                }
            }

            var hrefType = Utility.GetHrefType(item.Href);

            switch (hrefType)
            {
            case HrefType.AbsolutePath:
            case HrefType.RelativeFile:
                if (item.Items != null && item.Items.Count > 0)
                {
                    for (int i = 0; i < item.Items.Count; i++)
                    {
                        item.Items[i] = ResolveItem(new TocItemInfo(file, item.Items[i]), stack).Content;
                    }
                    if (string.IsNullOrEmpty(item.TopicHref) && string.IsNullOrEmpty(item.TopicUid))
                    {
                        var defaultItem = GetDefaultHomepageItem(item);
                        if (defaultItem != null)
                        {
                            item.AggregatedHref = defaultItem.TopicHref;
                            item.AggregatedUid  = defaultItem.TopicUid;
                        }
                    }
                }
                if (string.IsNullOrEmpty(item.TopicHref))
                {
                    // Get homepage from TocHref if href/topicHref is null or empty
                    if (string.IsNullOrEmpty(item.Href) && string.IsNullOrEmpty(item.TopicUid) && tocFileModel != null)
                    {
                        stack.Push(file);
                        var resolved = ResolveItem(tocFileModel, stack).Content;
                        stack.Pop();
                        item.Href     = resolved.TopicHref ?? resolved.AggregatedHref;
                        item.TopicUid = resolved.TopicUid ?? resolved.AggregatedUid;
                    }
                    // Use TopicHref in output model
                    item.TopicHref = item.Href;
                }
                break;

            case HrefType.RelativeFolder:
            {
                if (tocFileModel != null)
                {
                    Logger.LogWarning($"Href {item.Href} is overwritten by tocHref {item.TocHref}");
                }
                else
                {
                    var relativeFolder = (RelativePath)file.File + (RelativePath)item.Href;
                    var tocFilePath    = relativeFolder + (RelativePath)Constants.TableOfContents.YamlTocFileName;

                    var tocFile = file.ChangeFile(tocFilePath);

                    // First, try finding toc.yml under the relative folder
                    // Second, try finding toc.md under the relative folder
                    if (!_collection.TryGetValue(tocFile.FullPath, out tocFileModel))
                    {
                        tocFilePath = relativeFolder + (RelativePath)Constants.TableOfContents.MarkdownTocFileName;
                        tocFile     = file.ChangeFile(tocFilePath);
                        if (!_collection.TryGetValue(tocFile.FullPath, out tocFileModel))
                        {
                            var message =
                                $"Unable to find either {Constants.TableOfContents.YamlTocFileName} or {Constants.TableOfContents.MarkdownTocFileName} inside {item.Href}. Make sure the file is included in config file docfx.json!";
                            Logger.LogWarning(message);
                            break;
                        }
                    }

                    item.TocHref = tocFilePath - (RelativePath)file.File;
                }

                // Get homepage from TocHref if TopicHref/TopicUid is not specified
                if (string.IsNullOrEmpty(item.TopicHref) && string.IsNullOrEmpty(item.TopicUid))
                {
                    stack.Push(file);
                    var resolved = ResolveItem(tocFileModel, stack).Content;
                    stack.Pop();
                    item.Href     = item.TopicHref = resolved.TopicHref ?? resolved.AggregatedHref;
                    item.TopicUid = resolved.TopicUid ?? resolved.AggregatedUid;
                }
                else
                {
                    item.Href = item.TopicHref;
                }

                if (item.Items != null)
                {
                    for (int i = 0; i < item.Items.Count; i++)
                    {
                        item.Items[i] = ResolveItem(new TocItemInfo(file, item.Items[i]), stack).Content;
                    }
                }
            }
            break;

            case HrefType.MarkdownTocFile:
            case HrefType.YamlTocFile:
            {
                var              href        = (RelativePath)item.Href;
                var              tocFilePath = (RelativePath)file.File + href;
                var              tocFile     = file.ChangeFile(tocFilePath);
                TocItemInfo      referencedTocFileModel;
                TocItemViewModel referencedToc;
                stack.Push(file);
                if (_collection.TryGetValue(tocFile.FullPath, out referencedTocFileModel) || _notInProjectTocCache.TryGetValue(tocFile, out referencedTocFileModel))
                {
                    referencedTocFileModel = ResolveItem(referencedTocFileModel, stack);
                    referencedTocFileModel.IsReferenceToc = true;
                    referencedToc = referencedTocFileModel.Content;
                }
                else
                {
                    // It is acceptable that the referenced toc file is not included in docfx.json, as long as it can be found locally
                    referencedTocFileModel = new TocItemInfo(tocFile, TocHelper.LoadSingleToc(tocFile.FullPath));

                    referencedTocFileModel         = ResolveItem(referencedTocFileModel, stack);
                    referencedToc                  = referencedTocFileModel.Content;
                    _notInProjectTocCache[tocFile] = referencedTocFileModel;
                }
                stack.Pop();
                // For referenced toc, content from referenced toc is expanded as the items of current toc item,
                // Href is reset to the homepage of current toc item
                item.Href = item.TopicHref;
                var referencedTocClone = referencedToc.Items?.Clone();

                // For [reference](a/toc.md), and toc.md contains not-exist.md, the included not-exist.md should be resolved to a/not-exist.md
                item.Items = UpdateOriginalHref(referencedTocClone, href);
            }
            break;

            default:
                break;
            }

            var relativeToFile = (RelativePath)file.File;

            item.OriginalHref      = item.Href;
            item.OriginalTocHref   = item.TocHref;
            item.OriginalTopicHref = item.TopicHref;
            item.OriginalHomepage  = item.Homepage;
            item.Href      = NormalizeHref(item.Href, relativeToFile);
            item.TocHref   = NormalizeHref(item.TocHref, relativeToFile);
            item.TopicHref = NormalizeHref(item.TopicHref, relativeToFile);
            item.Homepage  = NormalizeHref(item.Homepage, relativeToFile);

            wrapper.IsResolved = true;

            // for backward compatibility
            if (item.Href == null && item.Homepage == null)
            {
                item.Href     = item.TocHref;
                item.Homepage = item.TopicHref;
            }

            return(wrapper);
        }