示例#1
0
        public MarkupResult Markup(string content, string filePath, bool enableValidation)
        {
            if (content == null)
            {
                throw new ArgumentNullException(nameof(content));
            }

            if (filePath == null)
            {
                throw new ArgumentException("file path can't be null or empty.");
            }

            var pipeline = CreateMarkdownPipeline(isInline: false, enableValidation: enableValidation);

            using (InclusionContext.PushFile((RelativePath)filePath))
            {
                return(new MarkupResult
                {
                    Html = Markdown.ToHtml(content, pipeline),
                    Dependency = InclusionContext.Dependencies.Select(file => (string)(RelativePath)file).ToImmutableArray()
                });
            }
        }
示例#2
0
        public void TestGetSchemaName()
        {
            const string expectedSchemaName = "YamlMime:ModuleUnit";
            const string yamlFilename       = "moduleunit.yml";
            const string yamlContent        = @"### YamlMime:ModuleUnit
uid: learn.azure.introduction";

            File.WriteAllText(yamlFilename, yamlContent);
            InclusionContext.PushFile(yamlFilename);
            InclusionContext.PushInclusion("introduction-included.md");

            string schemaName = string.Empty;

            var rewriter = MarkdownObjectRewriterFactory.FromValidator(
                MarkdownObjectValidatorFactory.FromLambda <MarkdownDocument>(
                    root =>
            {
                schemaName = root.GetData("SchemaName")?.ToString();
            })
                );
            var html = Markup("# Hello World", rewriter, null);

            Assert.Equal(expectedSchemaName, schemaName);
        }
        /// <summary>
        /// Parses the actual markdown down to html
        /// </summary>
        /// <param name="markdown"></param>
        /// <returns></returns>
        public override string Parse(string markdown)
        {
            var options = mmApp.Configuration.MarkdownOptions;

            var builder = new MarkdownPipelineBuilder();

            var errors = Array.Empty <string>();
            var tokens = new Dictionary <string, string>();
            var files  = new Dictionary <string, string>();

            var actualErrors       = new List <string>();
            var actualDependencies = new HashSet <string>();

            var context = new MarkdownContext(
                getToken: key => tokens.TryGetValue(key, out var value) ? value : null,
                logInfo: (a, b, c, d) => { },
                logSuggestion: Log("suggestion"),
                logWarning: Log("warning"),
                logError: Log("error"),
                readFile: ReadFile);


            // Fake root path to what MM sees as the root path (.markdown, project file, project open etc.)
            string filePath = mmApp.Model.ActiveDocument?.Filename;

            if (string.IsNullOrEmpty(filePath) || filePath.Equals("untitled", StringComparison.OrdinalIgnoreCase))
            {
                filePath = mmApp.Model.ActiveDocument?.PreviewWebRootPath;
                if (string.IsNullOrEmpty(filePath))
                {
                    filePath = "preview.md";
                }
                else
                {
                    filePath += "\\preview";
                }
            }

            files.Add(filePath, markdown);


            builder = builder.UseEmphasisExtras(EmphasisExtraOptions.Strikethrough)
                      .UseAutoIdentifiers(AutoIdentifierOptions.GitHub)
                      .UseMediaLinks()
                      .UsePipeTables()
                      .UseAutoLinks()
                      .UseHeadingIdRewriter()
                      .UseIncludeFile(context)
                      .UseCodeSnippet(context)
                      .UseDFMCodeInfoPrefix()
                      .UseQuoteSectionNote(context)
                      .UseXref()
                      .UseEmojiAndSmiley(false)
                      .UseTabGroup(context)
                      .UseMonikerRange(context)
                      .UseInteractiveCode()
                      .UseRow(context)
                      .UseNestedColumn(context)
                      .UseTripleColon(context)
                      .UseNoloc();



            builder = RemoveUnusedExtensions(builder);
            builder = builder
                      .UseYamlFrontMatter()
                      .UseLineNumber();

            if (options.NoHtml)
            {
                builder = builder.DisableHtml();
            }

            if (UsePragmaLines)
            {
                builder = builder.UsePragmaLines();
            }

            var pipeline = builder.Build();

            string html;

            using (InclusionContext.PushFile(filePath))
            {
                html = Markdown.ToHtml(markdown, pipeline);
            }

            html = ParseFontAwesomeIcons(html);


            if (mmApp.Configuration.MarkdownOptions.RenderLinksAsExternal)
            {
                html = ParseExternalLinks(html);
            }

            if (!mmApp.Configuration.MarkdownOptions.AllowRenderScriptTags)
            {
                html = HtmlUtils.SanitizeHtml(html);
            }


            return(html);


            MarkdownContext.LogActionDelegate Log(string level)
            {
                return((code, message, origin, line) => actualErrors.Add(code));
            }

            // Handler to fix up file paths for nested/included documents
            (string content, object file) ReadFile(string path, MarkdownObject origin)
            {
                string key;

                var rootPath = mmApp.Model.ActiveDocument?.PreviewWebRootPath;

                if (rootPath == null)
                {
                    rootPath = Path.GetDirectoryName(files.FirstOrDefault().Key);
                }


                string parentDocPath = null; //relativeTo as string;   NOT PROVIDEd BY DOCFX ANYMORE???

                //if (!string.IsNullOrEmpty(parentDocPath))
                //    parentDocPath = Path.GetDirectoryName(parentDocPath);


                //fully qualified path
                if (path.Contains(":/") || path.Contains(":\\"))
                {
                    key = path;
                }
                else if (!string.IsNullOrEmpty(rootPath) && path.StartsWith("~/"))
                {
                    path = path.Substring(2);
                    key  = Path.Combine(rootPath, path).Replace('\\', '/');
                }
                // Site relative  path
                else if (!string.IsNullOrEmpty(rootPath) && path.StartsWith("/"))
                {
                    path = path.Substring(1);
                    key  = Path.Combine(rootPath, path).Replace('\\', '/');
                }
                // Site relative path
                else if (!string.IsNullOrEmpty(parentDocPath))
                {
                    key = Path.GetFullPath(Path.Combine(parentDocPath, path));
                }
                else
                {
                    key = path;
                }

                actualDependencies.Add(key);

                files.TryGetValue(key, out var value);
                if (value == null)
                {
                    try
                    {
                        value = File.ReadAllText(key)?.Trim();
                    }
                    catch
                    {
                    }
                }

                if (value == null)
                {
                    return(null, null);
                }

                return(value, key as object);
            }
        }
示例#4
0
        public static void VerifyMarkup(
            string markdown,
            string html,
            string[] errors       = null,
            string[] dependencies = null,
            bool lineNumber       = false,
            string filePath       = "test.md",
            Dictionary <string, string> tokens = null,
            Dictionary <string, string> files  = null,
            Action <MarkdownObject> verifyAST  = null)
        {
            errors = errors ?? Array.Empty <string>();
            tokens = tokens ?? new Dictionary <string, string>();
            files  = files ?? new Dictionary <string, string>();

            var actualErrors       = new List <string>();
            var actualDependencies = new HashSet <string>();

            var markdownContext = new MarkdownContext(
                getToken: key => tokens.TryGetValue(key, out var value) ? value : null,
                logInfo: (a, b, c, d) => { },
                logSuggestion: Log("suggestion"),
                logWarning: Log("warning"),
                logError: Log("error"),
                readFile: ReadFile);

            var pipelineBuilder = new MarkdownPipelineBuilder()
                                  .UseDocfxExtensions(markdownContext)
                                  .UseYamlFrontMatter();

            if (lineNumber)
            {
                pipelineBuilder.UseLineNumber();
            }

            var pipeline = pipelineBuilder.Build();

            using (InclusionContext.PushFile(filePath))
            {
                var actualHtml = Markdown.ToHtml(markdown, pipeline);

                if (html != null)
                {
                    Assert.Equal(
                        html.Replace("\r", "").Replace("\n", ""),
                        actualHtml.Replace("\r", "").Replace("\n", ""));
                }

                Assert.Equal(errors.OrderBy(_ => _), actualErrors.OrderBy(_ => _));

                if (dependencies != null)
                {
                    Assert.Equal(dependencies.OrderBy(_ => _), actualDependencies.OrderBy(_ => _));
                }
            }

            MarkdownContext.LogActionDelegate Log(string level)
            {
                return((code, message, origin, line) => actualErrors.Add(code));
            }

            (string content, object file) ReadFile(string path, object relativeTo, MarkdownObject origin)
            {
                var key = Path.Combine(Path.GetDirectoryName(relativeTo.ToString()), path).Replace('\\', '/');

                if (path.StartsWith("~/"))
                {
                    path = path.Substring(2);
                    key  = path;
                }

                actualDependencies.Add(path);
                return(files.TryGetValue(key, out var value) ? (value, key) : default);
示例#5
0
        /// <summary>
        /// Parses the actual markdown down to html
        /// </summary>
        /// <param name="markdown"></param>
        /// <returns></returns>
        public override string Parse(string markdown)
        {
            var options = mmApp.Configuration.MarkdownOptions;

            var builder = new MarkdownPipelineBuilder();

            var errors = Array.Empty <string>();
            var tokens = new Dictionary <string, string>();
            var files  = new Dictionary <string, string>();

            var actualErrors       = new List <string>();
            var actualDependencies = new HashSet <string>();

            var context = new MarkdownContext(
                getToken: key => tokens.TryGetValue(key, out var value) ? value : null,
                logInfo: (a, b, c, d) => { },
                logSuggestion: Log("suggestion"),
                logWarning: Log("warning"),
                logError: Log("error"),
                readFile: ReadFile);


            // Fake root path to what MM sees as the root path (.markdown, project file, project open etc.)
            string filePath = mmApp.Model.ActiveDocument?.Filename;

            if (string.IsNullOrEmpty(filePath) || filePath.Equals("untitled", StringComparison.OrdinalIgnoreCase))
            {
                filePath = mmApp.Model.ActiveDocument?.PreviewWebRootPath;
                if (string.IsNullOrEmpty(filePath))
                {
                    filePath = "preview.md";
                }
                else
                {
                    filePath += "\\preview";
                }
            }
            files.Add(filePath, markdown);


            builder = builder.UseEmphasisExtras(EmphasisExtraOptions.Strikethrough)
                      .UseAutoIdentifiers(AutoIdentifierOptions.GitHub)
                      .UseMediaLinks()
                      .UsePipeTables()
                      .UseAutoLinks()
                      .UseHeadingIdRewriter()
                      .UseIncludeFile(context)
                      .UseCodeSnippet(context)
                      .UseDFMCodeInfoPrefix()
                      .UseQuoteSectionNote(context)
                      .UseXref()
                      .UseEmojiAndSmiley(false)
                      .UseTabGroup(context)
                      .UseMonikerRange(context)
                      .UseInteractiveCode()
                      .UseRow(context)
                      .UseNestedColumn(context)
                      .UseTripleColon(context)
                      .UseNoloc();



            builder = RemoveUnusedExtensions(builder);
            builder = builder
                      .UseYamlFrontMatter()
                      .UseLineNumber();

            if (options.NoHtml)
            {
                builder = builder.DisableHtml();
            }

            if (UsePragmaLines)
            {
                builder = builder.UsePragmaLines();
            }

            var pipeline = builder.Build();

            string html;

            try
            {
                using (InclusionContext.PushFile(filePath))
                {
                    html = Markdown.ToHtml(markdown, pipeline);
                }

                html = ParseFontAwesomeIcons(html);
            }
            catch (Exception ex)
            {
                if (markdown.Length > 10000)
                {
                    markdown = markdown.Substring(0, 10000);
                }

                mmApp.Log("Unable to render Markdown Document (docFx)\n" + markdown, ex, logLevel: LogLevels.Warning);
                html = $@"
<h1><i class='fa fa-warning text-error'></i> Unable to render Markdown Document</h1>

<p>
   An error occurred trying to parse the Markdown document to HTML:
</p>

<b style='font-size: 1.2em'>{ex.Message}</b>

<p>
    <a id='hrefShow' href='#0' style='font-size: 0.8em; font-weight: normal'>more info...</a>
</p>

<div id='detail' style='display:none'>


<p style='margin-top: 2em'>
    <b>Markdown Parser</b>: {options.MarkdownParserName}
</p>


<pre style='padding: 8px; background: #eee; color: #333' >{System.Net.WebUtility.HtmlEncode(StringUtils.NormalizeIndentation(ex.StackTrace))}</pre>
</div>

<script>
$('#hrefShow').click(function () {{ $('#detail').show(); }});
</script>
";
                return(html);
            }

            if (mmApp.Configuration.MarkdownOptions.RenderLinksAsExternal)
            {
                html = ParseExternalLinks(html);
            }

            if (!mmApp.Configuration.MarkdownOptions.AllowRenderScriptTags)
            {
                html = HtmlUtils.SanitizeHtml(html);
            }


            return(html);


            MarkdownContext.LogActionDelegate Log(string level)
            {
                return((code, message, origin, line) => actualErrors.Add(code));
            }

            // Handler to fix up file paths for nested/included documents
            (string content, object file) ReadFile(string path, object relativeTo, MarkdownObject origin)
            {
                string key;
                var    relativeDocumentPath = relativeTo as string;

                var rootPath = mmApp.Model.ActiveDocument?.PreviewWebRootPath;

                if (rootPath == null)
                {
                    rootPath = Path.GetDirectoryName(files.FirstOrDefault().Key);
                }
                var parentDocPath = relativeTo as string;

                if (!string.IsNullOrEmpty(parentDocPath))
                {
                    parentDocPath = Path.GetDirectoryName(parentDocPath);
                }


                //fully qualified path
                if (path.Contains(":/") || path.Contains(":\\"))
                {
                    key = path;
                }
                else if (!string.IsNullOrEmpty(rootPath) && path.StartsWith("~/"))
                {
                    path = path.Substring(2);
                    key  = Path.Combine(rootPath, path).Replace('\\', '/');
                }
                // Site relative  path
                else if (!string.IsNullOrEmpty(rootPath) && path.StartsWith("/"))
                {
                    path = path.Substring(1);
                    key  = Path.Combine(rootPath, path).Replace('\\', '/');
                }
                // Site relative path
                else if (!string.IsNullOrEmpty(parentDocPath))
                {
                    key = Path.GetFullPath(Path.Combine(parentDocPath, path));
                }
                else
                {
                    key = path;
                }

                actualDependencies.Add(key);

                files.TryGetValue(key, out var value);
                if (value == null)
                {
                    try
                    {
                        value = File.ReadAllText(key)?.Trim();
                    }catch { }
                }

                if (value == null)
                {
                    return(null, null);
                }

                return(value, key as object);
            }
        }