// @ts-check "use strict"; const { addError, forEachLine, htmlElementRe, withinAnyRange, unescapeMarkdown } = require("../helpers"); const { codeBlockAndSpanRanges, lineMetadata, referenceLinkImageData } = require("./cache"); const linkDestinationRe = /]\(\s*$/; // See https://spec.commonmark.org/0.29/#autolinks const emailAddressRe = // eslint-disable-next-line max-len /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; module.exports = { "names": [ "MD033", "no-inline-html" ], "description": "Inline HTML", "tags": [ "html" ], "function": function MD033(params, onError) { let allowedElements = params.config.allowed_elements; allowedElements = Array.isArray(allowedElements) ? allowedElements : []; allowedElements = allowedElements.map((element) => element.toLowerCase()); const exclusions = codeBlockAndSpanRanges(); const { references, definitionLineIndices } = referenceLinkImageData(); for (const datas of references.values()) { for (const data of datas) { const [ lineIndex, index, , textLength, labelLength ] = data; if (labelLength > 0) { exclusions.push([ lineIndex, index + 3 + textLength, labelLength ]); } } } forEachLine(lineMetadata(), (line, lineIndex, inCode) => { let match = null; // eslint-disable-next-line no-unmodified-loop-condition while (!inCode && ((match = htmlElementRe.exec(line)) !== null)) { const [ tag, content, element ] = match; if ( !allowedElements.includes(element.toLowerCase()) && !tag.endsWith("\\>") && !emailAddressRe.test(content) && !withinAnyRange(exclusions, lineIndex, match.index, tag.length) && !definitionLineIndices.includes(lineIndex) ) { const prefix = line.substring(0, match.index); if (!linkDestinationRe.test(prefix)) { const unescaped = unescapeMarkdown(prefix + "<", "_"); if (!unescaped.endsWith("_")) { addError(onError, lineIndex + 1, "Element: " + element, undefined, [ match.index + 1, tag.length ]); } } } } }); } };