"use strict"; (function main() { // Dependencies var markdownit = window.markdownit; var markdownlint = window.markdownlint.library; var helpers = window.markdownlint.helpers; var micromark = window.micromarkBrowser; var micromarkHtml = window.micromarkHtmlBrowser; // DOM elements var markdown = document.getElementById("markdown"); var markup = document.getElementById("markup"); var numbered = document.getElementById("numbered"); var violations = document.getElementById("violations"); var form = document.getElementsByTagName("form")[0]; var openFile = document.getElementById("openFile"); var copyLink = document.getElementById("copyLink"); // Variables var newLineRe = /\r\n|\r|\n/; var hashPrefix = "%m"; var allLintErrors = []; // Do-nothing function function noop() {} // Sanitize string for HTML display function sanitize(str) { return str .replace(/&/g, "&") .replace(//g, ">"); } // Renders Markdown to HTML function render(markdown) { const match = /^\?renderer=([a-z-]+)$/.exec(window.location.search); const renderer = match ? match[1] : "micromark"; if (renderer === "markdown-it") { return markdownit({ "html": true }).render(markdown); } else if (renderer === "micromark") { const parseOptions = { "extensions": [ micromark.gfmAutolinkLiteral(), micromark.gfmFootnote(), micromark.gfmTable(), micromark.math() ] }; const context = micromark.parse(parseOptions); const chunks = micromark.preprocess()(markdown, undefined, true); const events = micromark.postprocess(context.document().write(chunks)); const compileOptions = { "allowDangerousHtml": true, "htmlExtensions": [ micromarkHtml.gfmAutolinkLiteralHtml(), micromarkHtml.gfmFootnoteHtml(), micromarkHtml.gfmTableHtml(), micromarkHtml.mathHtml() ] }; try { return micromarkHtml.compile(compileOptions)(events); } catch (error) { return `[Exception: "${error}"]`; } } return `[Unsupported renderer "${renderer}"]`; } // Handle input function onMarkdownInput() { // Markdown var content = markdown.value; // Markup markup.innerHTML = render(content); // Numbered var lines = content.split(newLineRe); var padding = lines.length.toString().replace(/\d/g, " "); numbered.innerHTML = lines .map(function mapNumberedLine(line, index) { line = sanitize(line); index++; var paddedIndex = (padding + index).slice(-padding.length); return "" + paddedIndex + ": " + line + ""; }).join("\n"); // Violations var options = { "strings": { "content": content }, "config": { "MD013": false }, "handleRuleFailures": true }; allLintErrors = markdownlint.sync(options).content; violations.innerHTML = allLintErrors.map(function mapResult(result) { var ruleName = result.ruleNames.slice(0, 2).join(" / "); return "" + result.lineNumber + " - " + ruleName + " " + result.ruleDescription + (result.errorDetail ? " [" + sanitize(result.errorDetail) + "]" : "") + (result.errorContext ? " [Context: \"" + sanitize(result.errorContext) + "\"]" : "") + (result.fixInfo ? " [Fix]" : ""); }).join("
"); } // Load from a string or File object function loadMarkdown(source) { // Reset input element form.reset(); if (typeof source === "string") { // Update from string markdown.value = source; onMarkdownInput(); } else { // Update from File object source.text().then((text) => { markdown.value = text; onMarkdownInput(); }); } } // Handle drag-and-drop function onDragOver(e) { if (e.dataTransfer && e.dataTransfer.dropEffect) { e.dataTransfer.dropEffect = "link"; e.preventDefault(); } } function onDrop(e) { if (e.dataTransfer && e.dataTransfer.files) { loadMarkdown(e.dataTransfer.files[0]); e.preventDefault(); } } // Handle file open function onOpenFileChange(e) { if (e.target && e.target.files) { loadMarkdown(e.target.files[0]); } } // Handle violation navigation function onViolationClick(e) { switch (e.target.hash) { case "#fix": var errors = e.shiftKey ? allLintErrors : [ JSON.parse(decodeURIComponent(e.target.target)) ]; var fixed = helpers.applyFixes(markdown.value, errors); markdown.value = fixed; onMarkdownInput(); e.preventDefault(); break; case "#line": var line = document.getElementById("l" + e.target.target); if (line) { var highlighted = document.getElementsByClassName("highlight"); Array.prototype.forEach.call( highlighted, function forElement(element) { element.classList.remove("highlight"); } ); line.classList.add("highlight"); line.scrollIntoView(); } e.preventDefault(); break; default: break; } } // Updates the URL hash and copies the URL to the clipboard function onCopyLinkClick(e) { window.location.hash = encodeURIComponent(hashPrefix + markdown.value); if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(window.location).then(noop, noop); } else { /* eslint-disable-next-line no-alert */ alert("Document URL updated, select and copy it now."); } e.preventDefault(); } // Show library version document.getElementById("version").textContent = "(v" + markdownlint.getVersion() + ")"; // Add event listeners document.body.addEventListener("dragover", onDragOver); document.body.addEventListener("drop", onDrop); openFile.addEventListener("change", onOpenFileChange); markdown.addEventListener("input", onMarkdownInput); violations.addEventListener("click", onViolationClick, true); copyLink.addEventListener("click", onCopyLinkClick); markdown.value = [ "## Introduction", "", "`markdownlint` is a [Node.js](https://nodejs.org/) style checker and lint tool for [Markdown](https://en.wikipedia.org/wiki/Markdown)/[CommonMark](https://commonmark.org/) files to automatically validate content, prevent rendering problems, and promote consistency.", "This page offers an easy way to try it out interactively!", "", "#### Instructions", "", "Type or paste `Markdown ` content in the upper-left box, drag-and-drop a file, or open one with the chooser at the top.", "Content gets parsed and displayed in the upper-right box; rule violations (if any) show up in the lower-right box.", "Click a violation for information about it or click its line number to highlighted it in the lower-left box.", "", "> *Note*: [All rules](https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md) are enabled except [MD013/line-length](https://github.com/DavidAnson/markdownlint/blob/main/doc/md013.md).", "", "", "#### Resources", "* [`markdownlint` on GitHub](https://github.com/DavidAnson/markdownlint)", "* [`markdownlint` on npm](https://www.npmjs.com/package/markdownlint)", "* [Markdown specification](https://daringfireball.net/projects/markdown/)", "*\t[CommonMark specification](https://commonmark.org/)", "", "#### Thanks", "", "[`markdownlint/Ruby`](https://github.com/markdownlint/markdownlint) for the inspiration and [`markdown-it`](https://github.com/markdown-it/markdown-it) for the parser and interactive demo idea!", "" ].join("\n"); // Update Markdown from hash (if present) if (window.location.hash) { try { var decodedHash = decodeURIComponent(window.location.hash.substring(1)); if (hashPrefix === decodedHash.substring(0, hashPrefix.length)) { markdown.value = decodedHash.substring(hashPrefix.length); } /* eslint-disable-next-line unicorn/prefer-optional-catch-binding */ } catch (error) { // Invalid } } // Detect legacy browsers try { /* eslint-disable-next-line no-new */ new URL("https://example.com/"); /* eslint-disable-next-line unicorn/prefer-optional-catch-binding */ } catch (error) { markdown.value = [ "# Sorry", "", "This browser is not supported." ].join("\n"); } // Initialize onMarkdownInput(); }());