"use strict";
const require_runtime = require("../_virtual/_rolldown/runtime.js");
const require_index = require("../utils/index.js");
//#region lib/rules/use-v-on-exact.js
/**
* @fileoverview enforce usage of `exact` modifier on `v-on`.
* @author Armano
*/
var require_use_v_on_exact = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
	/**
	* @typedef { {name: string, node: VDirectiveKey, modifiers: string[] } } EventDirective
	*/
	const utils = require_index.default;
	const SYSTEM_MODIFIERS = /* @__PURE__ */ new Set([
		"ctrl",
		"shift",
		"alt",
		"meta"
	]);
	const GLOBAL_MODIFIERS = /* @__PURE__ */ new Set([
		"stop",
		"prevent",
		"capture",
		"self",
		"once",
		"passive",
		"native"
	]);
	/**
	* Finds and returns all keys for event directives
	*
	* @param {VStartTag} startTag Element startTag
	* @param {SourceCode} sourceCode The source code object.
	* @returns {EventDirective[]} [{ name, node, modifiers }]
	*/
	function getEventDirectives(startTag, sourceCode) {
		return utils.getDirectives(startTag, "on").map((attribute) => ({
			name: attribute.key.argument ? sourceCode.getText(attribute.key.argument) : "",
			node: attribute.key,
			modifiers: attribute.key.modifiers.map((modifier) => modifier.name)
		}));
	}
	/**
	* Checks whether given modifier is key modifier
	*
	* @param {string} modifier
	* @returns {boolean}
	*/
	function isKeyModifier(modifier) {
		return !GLOBAL_MODIFIERS.has(modifier) && !SYSTEM_MODIFIERS.has(modifier);
	}
	/**
	* Checks whether given modifier is system one
	*
	* @param {string} modifier
	* @returns {boolean}
	*/
	function isSystemModifier(modifier) {
		return SYSTEM_MODIFIERS.has(modifier);
	}
	/**
	* Checks whether given any of provided modifiers
	* has system modifier
	*
	* @param {string[]} modifiers
	* @returns {boolean}
	*/
	function hasSystemModifier(modifiers) {
		return modifiers.some(isSystemModifier);
	}
	/**
	* Groups all events in object,
	* with keys represinting each event name
	*
	* @param {EventDirective[]} events
	* @returns { { [key: string]: EventDirective[] } } { click: [], keypress: [] }
	*/
	function groupEvents(events) {
		/** @type { { [key: string]: EventDirective[] } } */
		const grouped = {};
		for (const event of events) {
			if (!grouped[event.name]) grouped[event.name] = [];
			grouped[event.name].push(event);
		}
		return grouped;
	}
	/**
	* Creates alphabetically sorted string with system modifiers
	*
	* @param {string[]} modifiers
	* @returns {string} e.g. "alt,ctrl,del,shift"
	*/
	function getSystemModifiersString(modifiers) {
		return modifiers.filter(isSystemModifier).sort((a, b) => a.localeCompare(b)).join(",");
	}
	/**
	* Creates alphabetically sorted string with key modifiers
	*
	* @param {string[]} modifiers
	* @returns {string} e.g. "enter,tab"
	*/
	function getKeyModifiersString(modifiers) {
		return modifiers.filter(isKeyModifier).sort((a, b) => a.localeCompare(b)).join(",");
	}
	/**
	* Compares two events based on their modifiers
	* to detect possible event leakeage
	*
	* @param {EventDirective} baseEvent
	* @param {EventDirective} event
	* @returns {boolean}
	*/
	function hasConflictedModifiers(baseEvent, event) {
		if (event.node === baseEvent.node || event.modifiers.includes("exact")) return false;
		const eventKeyModifiers = getKeyModifiersString(event.modifiers);
		const baseEventKeyModifiers = getKeyModifiersString(baseEvent.modifiers);
		if (eventKeyModifiers && baseEventKeyModifiers && eventKeyModifiers !== baseEventKeyModifiers) return false;
		const eventSystemModifiers = getSystemModifiersString(event.modifiers);
		const baseEventSystemModifiers = getSystemModifiersString(baseEvent.modifiers);
		return baseEvent.modifiers.length > 0 && baseEventSystemModifiers !== eventSystemModifiers && baseEventSystemModifiers.includes(eventSystemModifiers);
	}
	/**
	* Searches for events that might conflict with each other
	*
	* @param {EventDirective[]} events
	* @returns {EventDirective[]} conflicted events, without duplicates
	*/
	function findConflictedEvents(events) {
		/** @type {EventDirective[]} */
		const conflictedEvents = [];
		for (const event of events) conflictedEvents.push(...events.filter((evt) => !conflictedEvents.includes(evt)).filter(hasConflictedModifiers.bind(null, event)));
		return conflictedEvents;
	}
	module.exports = {
		meta: {
			type: "suggestion",
			docs: {
				description: "enforce usage of `exact` modifier on `v-on`",
				categories: ["vue3-essential", "vue2-essential"],
				url: "https://eslint.vuejs.org/rules/use-v-on-exact.html"
			},
			fixable: null,
			schema: [],
			messages: { considerExact: "Consider to use '.exact' modifier." }
		},
		/**
		* Creates AST event handlers for use-v-on-exact.
		*
		* @param {RuleContext} context - The rule context.
		* @returns {RuleListener} AST event handlers.
		*/
		create(context) {
			const sourceCode = context.sourceCode;
			return utils.defineTemplateBodyVisitor(context, { 
			/** @param {VStartTag} node */
VStartTag(node) {
				if (node.attributes.length === 0) return;
				const isCustomComponent = utils.isCustomComponent(node.parent);
				let events = getEventDirectives(node, sourceCode);
				if (isCustomComponent) events = events.filter((event) => event.modifiers.includes("native"));
				const grouppedEvents = groupEvents(events);
				for (const eventsInGroup of Object.values(grouppedEvents)) {
					if (!eventsInGroup.some((event) => hasSystemModifier(event.modifiers))) continue;
					const conflictedEvents = findConflictedEvents(eventsInGroup);
					for (const e of conflictedEvents) context.report({
						node: e.node,
						loc: e.node.loc,
						messageId: "considerExact"
					});
				}
			} });
		}
	};
}));
//#endregion
Object.defineProperty(exports, "default", {
	enumerable: true,
	get: function() {
		return require_use_v_on_exact();
	}
});
