Beispiel #1
0
 public TocItemInfo(FileAndType file, TocItemViewModel item)
 {
     Content = item;
     File = file;
     IsResolved = false;
     IsReferenceToc = false;
 }
Beispiel #2
0
        private void BuildCore(TocItemViewModel item, FileModel model, IHostService hostService)
        {
            if (item == null)
            {
                return;
            }

            var linkToUids = new HashSet<string>();
            var linkToFiles = new HashSet<string>();
            if (Utility.IsSupportedRelativeHref(item.Href))
            {
                linkToFiles.Add(ParseFile(item.Href));
            }

            if (Utility.IsSupportedRelativeHref(item.Homepage))
            {
                linkToFiles.Add(ParseFile(item.Homepage));
            }

            if (!string.IsNullOrEmpty(item.TopicUid))
            {
                linkToUids.Add(item.TopicUid);
            }

            model.LinkToUids = model.LinkToUids.Union(linkToUids);
            model.LinkToFiles = model.LinkToFiles.Union(linkToFiles);

            if (item.Items != null)
            {
                foreach (var i in item.Items)
                {
                    BuildCore(i, model, hostService);
                }
            }
        }
Beispiel #3
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
            };
        }
 private static void AssertTocEqual(TocItemViewModel expected, TocItemViewModel actual)
 {
     using (var swForExpected = new StringWriter())
     {
         YamlUtility.Serialize(swForExpected, expected);
         using (var swForActual = new StringWriter())
         {
             YamlUtility.Serialize(swForActual, actual);
             Assert.Equal(swForExpected.ToString(), swForActual.ToString());
         }
     }
 }
        public void ProcessMarkdownTocWithAbsoluteHrefShouldSucceed()
        {
            var content = @"
#[Topic1](/href1)
##Topic1.1
###[Topic1.1.1](/href1.1.1)
##[Topic1.2]()
#[Topic2](http://href.com)
";
            var toc = _fileCreator.CreateFile(content, FileType.MarkdownToc);
            FileCollection files = new FileCollection(_inputFolder);
            files.Add(DocumentType.Article, new[] { toc });
            BuildDocument(files);

            var outputRawModelPath = Path.Combine(_outputFolder, Path.ChangeExtension(toc, RawModelFileExtension));
            Assert.True(File.Exists(outputRawModelPath));
            var model = JsonUtility.Deserialize<TocItemViewModel>(outputRawModelPath);
            var expectedModel = new TocItemViewModel
            {
                Items = new TocViewModel
                {
                    new TocItemViewModel
                    {
                        Name = "Topic1",
                        Href = "/href1",
                        TopicHref = "/href1",
                        Items = new TocViewModel
                        {
                            new TocItemViewModel
                            {
                                Name = "Topic1.1",
                                Items = new TocViewModel
                                {
                                    new TocItemViewModel
                                    {
                                        Name = "Topic1.1.1",
                                        Href = "/href1.1.1",
                                        TopicHref = "/href1.1.1"
                                    }
                                }
                            },
                            new TocItemViewModel
                            {
                                Name = "Topic1.2",
                                Href = string.Empty,
                                TopicHref = string.Empty
                            }
                        }
                    },
                    new TocItemViewModel
                    {
                        Name = "Topic2",
                        Href = "http://href.com",
                        TopicHref = "http://href.com"
                    }
                }
            };

            AssertTocEqual(expectedModel, model);
        }
        public void ProcessYamlTocWithTocHrefShouldSucceed()
        {
            var file1 = _fileCreator.CreateFile(string.Empty, FileType.MarkdownContent);
            var file2 = _fileCreator.CreateFile(string.Empty, FileType.MarkdownContent, "sub1/sub2");
            var referencedToc = _fileCreator.CreateFile($@"
- name: Topic
  href: {Path.GetFileName(file2)}
", FileType.YamlToc, "sub1/sub2");
            var content = $@"
- name: Topic1
  tocHref: /Topic1/
  topicHref: /Topic1/index.html
  items:
    - name: Topic1.1
      tocHref: /Topic1.1/
      topicHref: /Topic1.1/index.html
    - name: Topic1.2
      tocHref: /Topic1.2/
      topicHref: /Topic1.2/index.html
- name: Topic2
  tocHref: {referencedToc}
  topicHref: {file2}
";
            var toc = _fileCreator.CreateFile(content, FileType.YamlToc);
            FileCollection files = new FileCollection(_inputFolder);
            files.Add(DocumentType.Article, new[] { file1, file2, toc, referencedToc });
            BuildDocument(files);
            var outputRawModelPath = Path.Combine(_outputFolder, Path.ChangeExtension(toc, RawModelFileExtension));

            Assert.True(File.Exists(outputRawModelPath));
            var model = JsonUtility.Deserialize<TocItemViewModel>(outputRawModelPath);
            var expectedModel = new TocItemViewModel
            {
                Items = new TocViewModel
                {
                    new TocItemViewModel
                    {
                        Name = "Topic1",
                        Href = "/Topic1/",
                        TocHref = "/Topic1/",
                        Homepage = "/Topic1/index.html",
                        TopicHref = "/Topic1/index.html",
                        Items = new TocViewModel
                        {
                            new TocItemViewModel
                            {
                                Name = "Topic1.1",
                                Href = "/Topic1.1/",
                                TocHref = "/Topic1.1/",
                                Homepage = "/Topic1.1/index.html",
                                TopicHref = "/Topic1.1/index.html",
                            },
                            new TocItemViewModel
                            {
                                Name = "Topic1.2",
                                Href = "/Topic1.2/",
                                TocHref = "/Topic1.2/",
                                Homepage = "/Topic1.2/index.html",
                                TopicHref = "/Topic1.2/index.html",
                            }
                        }
                    },
                    new TocItemViewModel
                    {
                        Name = "Topic2",
                        TocHref = referencedToc,
                        Href = referencedToc,
                        TopicHref = file2,
                        Homepage = file2,
                    }
                }
            };

            AssertTocEqual(expectedModel, model);
        }
        public void ProcessYamlTocWithReferencedTocShouldSucceed()
        {
            var file1 = _fileCreator.CreateFile(string.Empty, FileType.MarkdownContent);
            var file2 = _fileCreator.CreateFile(string.Empty, FileType.MarkdownContent, "sub1");
            var file3 = _fileCreator.CreateFile(string.Empty, FileType.MarkdownContent, "sub1/sub2");
            var referencedToc = _fileCreator.CreateFile($@"
- name: Topic
  href: {Path.GetFileName(file3)}
", FileType.YamlToc, "sub1/sub2");
            var subToc = _fileCreator.CreateFile($@"
#[Topic]({Path.GetFileName(file2)})
#[ReferencedToc](sub2/{Path.GetFileName(referencedToc)})
", FileType.MarkdownToc, "sub1");
            var content = $@"
- name: Topic1
  href: {file1}
  items:
    - name: Topic1.1
      href: {subToc}
      items:
        - name: Topic1.1.1
        - name: Topic1.1.2
    - name: Topic1.2
      href: {subToc}
      homepage: {file1}
- name: Topic2
  href: {referencedToc}
";
            var toc = _fileCreator.CreateFile(content, FileType.YamlToc);
            FileCollection files = new FileCollection(_inputFolder);
            files.Add(DocumentType.Article, new[] { file1, file2, file3, toc, subToc });
            BuildDocument(files);
            var outputRawModelPath = Path.Combine(_outputFolder, Path.ChangeExtension(toc, RawModelFileExtension));

            Assert.True(File.Exists(outputRawModelPath));
            var model = JsonUtility.Deserialize<TocItemViewModel>(outputRawModelPath);
            var expectedModel = new TocItemViewModel
            {
                Items = new TocViewModel
                {
                    new TocItemViewModel
                    {
                        Name = "Topic1",
                        Href = file1,
                        TopicHref = file1,
                        Items = new TocViewModel
                        {
                            new TocItemViewModel
                            {
                                Name = "Topic1.1",
                                Href = null, // For referenced toc, the content from the referenced toc is expanded as the items of current toc, and href is cleared
                                TopicHref = null,
                                Items = new TocViewModel
                                {
                                    new TocItemViewModel
                                    {
                                        Name = "Topic",
                                        Href = file2,
                                        TopicHref = file2,
                                    },
                                    new TocItemViewModel
                                    {
                                        Name = "ReferencedToc",
                                        Items = new TocViewModel
                                        {
                                            new TocItemViewModel
                                            {
                                                Name = "Topic",
                                                Href = file3,
                                                TopicHref = file3,
                                            }
                                        }
                                    }
                                }
                            },
                            new TocItemViewModel
                            {
                                Name = "Topic1.2",
                                Href = file1, // For referenced toc, href should be overwritten by homepage
                                TopicHref = file1,
                                Homepage = file1,
                                Items = new TocViewModel
                                {
                                    new TocItemViewModel
                                    {
                                        Name = "Topic",
                                        Href = file2,
                                        TopicHref = file2,
                                    },
                                    new TocItemViewModel
                                    {
                                        Name = "ReferencedToc",
                                        Items = new TocViewModel
                                        {
                                            new TocItemViewModel
                                            {
                                                Name = "Topic",
                                                Href = file3,
                                                TopicHref = file3,
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    new TocItemViewModel
                    {
                        Name = "Topic2",
                        Href = null,
                        Items = new TocViewModel
                        {
                            new TocItemViewModel
                            {
                                Name = "Topic",
                                Href = file3,
                                TopicHref = file3,
                            }
                        }
                    }
                }
            };

            AssertTocEqual(expectedModel, model);

            // Referenced TOC File should not exist
            var referencedTocPath = Path.Combine(_outputFolder, Path.ChangeExtension(subToc, RawModelFileExtension));
            Assert.False(File.Exists(referencedTocPath));
        }
        public void ProcessYamlTocWithFolderShouldSucceed()
        {
            var file1 = _fileCreator.CreateFile(string.Empty, FileType.MarkdownContent);
            var file2 = _fileCreator.CreateFile(string.Empty, FileType.MarkdownContent, "sub");
            var subToc = _fileCreator.CreateFile($@"
#[Topic]({Path.GetFileName(file2)})
", FileType.MarkdownToc, "sub");
            var content = $@"
- name: Topic1
  href: {file1}
  items:
    - name: Topic1.1
      href: {file1}
      homepage: {file2}
    - name: Topic1.2
      href: sub/
      homepage: {file1}
- name: Topic2
  href: sub/
";
            var toc = _fileCreator.CreateFile(content, FileType.YamlToc);
            FileCollection files = new FileCollection(_inputFolder);
            files.Add(DocumentType.Article, new[] { file1, file2, toc, subToc });
            BuildDocument(files);
            var outputRawModelPath = Path.Combine(_outputFolder, Path.ChangeExtension(toc, RawModelFileExtension));
            Assert.True(File.Exists(outputRawModelPath));
            var model = JsonUtility.Deserialize<TocItemViewModel>(outputRawModelPath);
            var expectedModel = new TocItemViewModel
            {
                Items = new TocViewModel
                {
                    new TocItemViewModel
                    {
                        Name = "Topic1",
                        Href = file1,
                        TopicHref = file1,
                        Items = new TocViewModel
                        {
                            new TocItemViewModel
                            {
                                Name = "Topic1.1",
                                Href = file1, // For relative file, href keeps unchanged
                                Homepage = file2, // Homepage always keeps unchanged
                                TopicHref = file2,
                            },
                            new TocItemViewModel
                            {
                                Name = "Topic1.2",
                                Href = file1, // For relative folder, href should be overwritten by homepage
                                Homepage = file1,
                                TopicHref = file1,
                                TocHref = "sub/toc.md",
                            }
                        }
                    },
                    new TocItemViewModel
                    {
                        Name = "Topic2",
                        Href = file2,
                        TopicHref = file2,
                        TocHref = "sub/toc.md",
                    }
                }
            };

            AssertTocEqual(expectedModel, model);
        }
Beispiel #9
0
        /// <summary>
        /// Valid homepage href should:
        /// 1. relative file path
        /// 2. refer to a file
        /// 3. folder is not supported
        /// 4. refer to an `uid`
        /// </summary>
        /// <param name="href"></param>
        /// <returns></returns>
        private bool IsValidHomepageLink(TocItemViewModel tocItem)
        {
            if (!string.IsNullOrEmpty(tocItem.TopicUid))
            {
                return true;
            }

            var hrefType = Utility.GetHrefType(tocItem.Href);
            if (hrefType == HrefType.RelativeFile)
            {
                return true;
            }

            return false;
        }
Beispiel #10
0
        private TocItemViewModel GetDefaultHomepageItem(TocItemViewModel toc)
        {
            if (toc == null || toc.Items == null)
            {
                return null;
            }

            foreach (var item in toc.Items)
            {
                var tocItem = TreeIterator.PreorderFirstOrDefault(item, s => s.Items, s => IsValidHomepageLink(s));
                if (tocItem != null)
                {
                    return tocItem;
                }
            }
            return null;
        }
Beispiel #11
0
        private void UpdateTocItemHref(TocItemViewModel toc, FileModel model, IDocumentBuildContext context)
        {
            if (toc.IsHrefUpdated) return;

            ResolveUid(toc, model, context);

            // Have to register TocMap after uid is resolved
            RegisterTocMap(toc, model.Key, context);

            toc.Homepage = ResolveHref(toc.Homepage, toc.OriginalHomepage, model, context, nameof(toc.Homepage));
            toc.Href = ResolveHref(toc.Href, toc.OriginalHref, model, context, nameof(toc.Href));
            toc.TocHref = ResolveHref(toc.TocHref, toc.OriginalTocHref, model, context, nameof(toc.TocHref));
            toc.TopicHref = ResolveHref(toc.TopicHref, toc.OriginalTopicHref, model, context, nameof(toc.TopicHref));

            if (toc.Items != null && toc.Items.Count > 0)
            {
                foreach (var item in toc.Items)
                {
                    UpdateTocItemHref(item, model, context);
                }
            }

            toc.IsHrefUpdated = true;
        }
Beispiel #12
0
 private void RegisterTocMap(TocItemViewModel item, string key, IDocumentBuildContext context)
 {
     // If tocHref is set, href is originally RelativeFolder type, and href is set to the homepage of TocHref,
     // So in this case, TocHref should be used to in TocMap
     // TODO: what if user wants to set TocHref?
     var tocHref = item.TocHref;
     var tocHrefType = Utility.GetHrefType(tocHref);
     if (tocHrefType == HrefType.MarkdownTocFile || tocHrefType == HrefType.YamlTocFile)
     {
         context.RegisterToc(key, tocHref);
     }
     else
     {
         var href = item.Href; // Should be original href from working folder starting with ~
         if (Utility.IsSupportedRelativeHref(href))
         {
             context.RegisterToc(key, href);
         }
     }
 }
Beispiel #13
0
        private void ResolveUid(TocItemViewModel item, FileModel model, IDocumentBuildContext context)
        {
            if (item.TopicUid != null)
            {
                var xref = GetXrefFromUid(item.TopicUid, model, context);
                if (xref != null)
                {
                    item.Href = item.TopicHref = xref.Href;
                    if (string.IsNullOrEmpty(item.Name))
                    {
                        item.Name = xref.Name;
                    }

                    string nameForCSharp;
                    if (string.IsNullOrEmpty(item.NameForCSharp) && xref.TryGetValue("name.csharp", out nameForCSharp))
                    {
                        item.NameForCSharp = nameForCSharp;
                    }
                    string nameForVB;
                    if (string.IsNullOrEmpty(item.NameForVB) && xref.TryGetValue("name.vb", out nameForVB))
                    {
                        item.NameForVB = nameForVB;
                    }
                }
            }
        }
Beispiel #14
0
            protected ParseState ApplyCore(ParseState state, int level, string text, string href, string uid = null)
            {
                if (level > state.Level + 1)
                {
                    return new ErrorState(state, level, $"Skip level is not allowed. Toc content: {text}");
                }

                // If current node is another node in higher or same level
                for (int i = state.Level; i >= level; --i)
                {
                    state.Parents.Pop();
                }

                var item = new TocItemViewModel
                {
                    Name = text,
                    Href = href,
                    Uid = uid
                };
                if (state.Parents.Count > 0)
                {
                    var parent = state.Parents.Peek();
                    if (parent.Items == null)
                    {
                        parent.Items = new TocViewModel();
                    }
                    parent.Items.Add(item);
                }
                else
                {
                    state.Root.Add(item);
                }
                state.Parents.Push(item);

                if (state.Level == level)
                {
                    return state;
                }
                return new NodeState(state, level);
            }