"use strict";
const require_runtime = require("../../../_virtual/_rolldown/runtime.js");
const require_index = require("../../../utils/index.js");
//#region lib/rules/syntaxes/utils/can-convert-to-v-slot.js
/**
* @author Yosuke Ota
* See LICENSE file in root directory for full license.
*/
var require_can_convert_to_v_slot = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
	const utils = require_index.default;
	/**
	* @typedef {object} SlotVForVariables
	* @property {VForExpression} expr
	* @property {VVariable[]} variables
	*/
	/**
	* @typedef {object} SlotContext
	* @property {VElement} element
	* @property {VAttribute | VDirective | null} slot
	* @property {VDirective | null} vFor
	* @property {SlotVForVariables | null} slotVForVars
	* @property {string} normalizedName
	*/
	/**
	* Checks whether the given element can use v-slot.
	* @param {VElement} element
	* @param {SourceCode} sourceCode
	* @param {ParserServices.TokenStore} tokenStore
	*/
	module.exports = function canConvertToVSlot(element, sourceCode, tokenStore) {
		const ownerElement = element.parent;
		if (ownerElement.type === "VDocumentFragment" || !utils.isCustomComponent(ownerElement) || ownerElement.name === "component") return false;
		const slot = getSlotContext(element, sourceCode);
		if (slot.vFor && !slot.slotVForVars) return false;
		return !hasSameSlotDirective(ownerElement, slot, sourceCode, tokenStore);
	};
	/**
	* @param {VElement} element
	* @param {SourceCode} sourceCode
	* @returns {SlotContext}
	*/
	function getSlotContext(element, sourceCode) {
		const slot = utils.getAttribute(element, "slot") || utils.getDirective(element, "bind", "slot");
		const vFor = utils.getDirective(element, "for");
		return {
			element,
			slot,
			vFor,
			slotVForVars: getSlotVForVariableIfUsingIterationVars(slot, vFor),
			normalizedName: getNormalizedName(slot, sourceCode)
		};
	}
	/**
	* Gets the `v-for` directive and variable that provide the variables used by the given `slot` attribute.
	* @param {VAttribute | VDirective | null} slot The current `slot` attribute node.
	* @param {VDirective | null} [vFor] The current `v-for` directive node.
	* @returns { SlotVForVariables | null } The SlotVForVariables.
	*/
	function getSlotVForVariableIfUsingIterationVars(slot, vFor) {
		if (!slot || !slot.directive) return null;
		const expr = vFor && vFor.value && vFor.value.expression;
		const variables = expr && getUsingIterationVars(slot.value, slot.parent.parent);
		return expr && variables && variables.length > 0 ? {
			expr,
			variables
		} : null;
	}
	/**
	* Gets iterative variables if a given expression node is using iterative variables that the element defined.
	* @param {VExpressionContainer|null} expression The expression node to check.
	* @param {VElement} element The element node which has the expression.
	* @returns {VVariable[]} The expression node is using iteration variables.
	*/
	function getUsingIterationVars(expression, element) {
		const vars = [];
		if (expression && expression.type === "VExpressionContainer") {
			for (const { variable } of expression.references) if (variable != null && variable.kind === "v-for" && variable.id.range[0] > element.startTag.range[0] && variable.id.range[1] < element.startTag.range[1]) vars.push(variable);
		}
		return vars;
	}
	/**
	* Get the normalized name of a given `slot` attribute node.
	* @param {VAttribute | VDirective | null} slotAttr node of `slot`
	* @param {SourceCode} sourceCode The source code.
	* @returns {string} The normalized name.
	*/
	function getNormalizedName(slotAttr, sourceCode) {
		if (!slotAttr) return "default";
		if (!slotAttr.directive) return slotAttr.value ? slotAttr.value.value : "default";
		return slotAttr.value ? `[${sourceCode.getText(slotAttr.value)}]` : "[null]";
	}
	/**
	* Checks whether parent element has the same slot as the given slot.
	* @param {VElement} ownerElement The parent element.
	* @param {SlotContext} targetSlot The SlotContext with a slot to check if they are the same.
	* @param {SourceCode} sourceCode
	* @param {ParserServices.TokenStore} tokenStore
	*/
	function hasSameSlotDirective(ownerElement, targetSlot, sourceCode, tokenStore) {
		for (const group of utils.iterateChildElementsChains(ownerElement)) {
			if (group.includes(targetSlot.element)) continue;
			for (const childElement of group) {
				const slot = getSlotContext(childElement, sourceCode);
				if (!targetSlot.slotVForVars || !slot.slotVForVars) {
					if (!targetSlot.slotVForVars && !slot.slotVForVars && targetSlot.normalizedName === slot.normalizedName) return true;
				} else if (equalSlotVForVariables(targetSlot.slotVForVars, slot.slotVForVars, tokenStore)) return true;
			}
		}
		return false;
	}
	/**
	* Determines whether the two given `v-slot` variables are considered to be equal.
	* @param {SlotVForVariables} a First element.
	* @param {SlotVForVariables} b Second element.
	* @param {ParserServices.TokenStore} tokenStore The token store.
	* @returns {boolean} `true` if the elements are considered to be equal.
	*/
	function equalSlotVForVariables(a, b, tokenStore) {
		if (a.variables.length !== b.variables.length) return false;
		if (!equal(a.expr.right, b.expr.right)) return false;
		const checkedVarNames = /* @__PURE__ */ new Set();
		const len = Math.min(a.expr.left.length, b.expr.left.length);
		for (let index = 0; index < len; index++) {
			const aPtn = a.expr.left[index];
			const bPtn = b.expr.left[index];
			const aVar = a.variables.find((v) => aPtn.range[0] <= v.id.range[0] && v.id.range[1] <= aPtn.range[1]);
			const bVar = b.variables.find((v) => bPtn.range[0] <= v.id.range[0] && v.id.range[1] <= bPtn.range[1]);
			if (aVar && bVar) {
				if (aVar.id.name !== bVar.id.name) return false;
				if (!equal(aPtn, bPtn)) return false;
				checkedVarNames.add(aVar.id.name);
			} else if (aVar || bVar) return false;
		}
		return a.variables.every((v) => checkedVarNames.has(v.id.name) || b.variables.some((bv) => v.id.name === bv.id.name));
		/**
		* Determines whether the two given nodes are considered to be equal.
		* @param {ASTNode} a First node.
		* @param {ASTNode} b Second node.
		* @returns {boolean} `true` if the nodes are considered to be equal.
		*/
		function equal(a, b) {
			if (a.type !== b.type) return false;
			return utils.equalTokens(a, b, tokenStore);
		}
	}
}));
//#endregion
Object.defineProperty(exports, "default", {
	enumerable: true,
	get: function() {
		return require_can_convert_to_v_slot();
	}
});
