/**
 * @fileoverview Rule to require alternative text for images in Markdown.
 * @author Pixel998
 */
//-----------------------------------------------------------------------------
// Imports
//-----------------------------------------------------------------------------
import { stripHtmlComments } from "../util.js";
//-----------------------------------------------------------------------------
// Type Definitions
//-----------------------------------------------------------------------------
/**
 * @import { Image, ImageReference } from "mdast";
 * @import { MarkdownRuleDefinition } from "../types.js";
 * @typedef {"altTextRequired"} RequireAltTextMessageIds
 * @typedef {[]} RequireAltTextOptions
 * @typedef {MarkdownRuleDefinition<{ RuleOptions: RequireAltTextOptions, MessageIds: RequireAltTextMessageIds }>} RequireAltTextRuleDefinition
 */
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
const imgTagPattern = /<img(?:\s(?:[^>"']|"[^"]*"|'[^']*')*)?\/?>/giu;
/**
 * Creates a regex to match HTML attributes
 * @param {string} name The attribute name to match
 * @returns {RegExp} Regular expression for matching the attribute
 */
function getHtmlAttributeRe(name) {
    return new RegExp(`\\s${name}(?:\\s*=\\s*['"]([^'"]*)['"])?`, "iu");
}
//-----------------------------------------------------------------------------
// Rule Definition
//-----------------------------------------------------------------------------
export default /** @satisfies {RequireAltTextRuleDefinition} */ ({
    meta: {
        type: "problem",
        docs: {
            recommended: true,
            description: "Require alternative text for images",
            url: "https://github.com/eslint/markdown/blob/main/docs/rules/require-alt-text.md",
        },
        messages: {
            altTextRequired: "Alternative text for image is required.",
        },
    },
    create(context) {
        const { sourceCode } = context;
        return {
            "image, imageReference"(
            /** @type {Image | ImageReference} */ node) {
                if (node.alt.trim().length === 0) {
                    context.report({
                        loc: node.position,
                        messageId: "altTextRequired",
                    });
                }
            },
            html(node) {
                const text = stripHtmlComments(sourceCode.getText(node));
                /** @type {RegExpExecArray | null} */
                let match;
                while ((match = imgTagPattern.exec(text)) !== null) {
                    const imgTag = match[0];
                    const ariaHiddenMatch = imgTag.match(getHtmlAttributeRe("aria-hidden"));
                    if (ariaHiddenMatch &&
                        ariaHiddenMatch[1] &&
                        ariaHiddenMatch[1].toLowerCase() === "true") {
                        continue;
                    }
                    const altMatch = imgTag.match(getHtmlAttributeRe("alt"));
                    if (!altMatch ||
                        (altMatch[1] &&
                            altMatch[1].trim().length === 0 &&
                            altMatch[1].length > 0)) {
                        const startOffset = // Adjust `imgTagPattern` match indices to the full source code.
                         match.index + node.position.start.offset;
                        const endOffset = startOffset + imgTag.length;
                        context.report({
                            loc: {
                                start: sourceCode.getLocFromIndex(startOffset),
                                end: sourceCode.getLocFromIndex(endOffset),
                            },
                            messageId: "altTextRequired",
                        });
                    }
                }
            },
        };
    },
});
