const require_runtime = require("../_virtual/_rolldown/runtime.js");
const require_index = require("../utils/index.js");
const require_index$1 = require("../utils/style-variables/index.js");
const require_property_references = require("../utils/property-references.js");
const require_comments = require("../utils/comments.js");
let _eslint_community_eslint_utils = require("@eslint-community/eslint-utils");
_eslint_community_eslint_utils = require_runtime.__toESM(_eslint_community_eslint_utils);
//#region lib/rules/no-unused-properties.ts
var import_utils = /* @__PURE__ */ require_runtime.__toESM(require_index.default);
const GROUP_PROPERTY = "props";
const GROUP_DATA = "data";
const GROUP_ASYNC_DATA = "asyncData";
const GROUP_COMPUTED_PROPERTY = "computed";
const GROUP_METHODS = "methods";
const GROUP_SETUP = "setup";
const GROUP_WATCHER = "watch";
const GROUP_EXPOSE = "expose";
const GROUP_INJECT = "inject";
const UNREFERENCED_UNKNOWN_MEMBER = "unknownMemberAsUnreferenced";
const UNREFERENCED_RETURN = "returnAsUnreferenced";
const PROPERTY_LABEL = {
	props: "property",
	data: "data",
	asyncData: "async data",
	computed: "computed property",
	methods: "method",
	setup: "property returned from `setup()`",
	inject: "inject",
	watch: "watch",
	provide: "provide",
	expose: "expose"
};
function findExpression(context, id) {
	const variable = import_utils.default.findVariableByIdentifier(context, id);
	if (!variable) return id;
	if (variable.defs.length === 1) {
		const def = variable.defs[0];
		if (def.type === "Variable" && def.parent.kind === "const" && def.node.init) {
			if (def.node.init.type === "Identifier") return findExpression(context, def.node.init);
			return def.node.init;
		}
	}
	return id;
}
/**
* Check if the given component property is marked as `@public` in JSDoc comments.
*/
function isPublicMember(property, sourceCode) {
	if (property.type === "object" && property.groupName !== "props") return isPublicProperty(property.property, sourceCode);
	return false;
}
/**
* Check if the given property node is marked as `@public` in JSDoc comments.
*/
function isPublicProperty(node, sourceCode) {
	const jsdoc = getJSDocFromProperty(node, sourceCode);
	if (jsdoc) return /(?:^|\s|\*)@public\b/u.test(jsdoc.value);
	return false;
}
/**
* Get the JSDoc comment for a given property node.
*/
function getJSDocFromProperty(node, sourceCode) {
	const jsdoc = findJSDocComment(node, sourceCode);
	if (jsdoc) return jsdoc;
	if (node.value.type === "FunctionExpression" || node.value.type === "ArrowFunctionExpression") return findJSDocComment(node.value, sourceCode);
	return null;
}
/**
* Finds a JSDoc comment for the given node.
*/
function findJSDocComment(node, sourceCode) {
	let currentNode = node;
	let tokenBefore = null;
	while (currentNode) {
		tokenBefore = sourceCode.getTokenBefore(currentNode, { includeComments: true });
		if (!tokenBefore || !_eslint_community_eslint_utils.default.isCommentToken(tokenBefore)) return null;
		if (tokenBefore.type === "Line") {
			currentNode = tokenBefore;
			continue;
		}
		break;
	}
	if (tokenBefore && require_comments.isJSDocComment(tokenBefore)) return tokenBefore;
	return null;
}
var no_unused_properties_default = {
	meta: {
		type: "suggestion",
		docs: {
			description: "disallow unused properties",
			categories: void 0,
			url: "https://eslint.vuejs.org/rules/no-unused-properties.html"
		},
		fixable: null,
		schema: [{
			type: "object",
			properties: {
				groups: {
					type: "array",
					items: { enum: [
						GROUP_PROPERTY,
						GROUP_DATA,
						GROUP_ASYNC_DATA,
						GROUP_COMPUTED_PROPERTY,
						GROUP_METHODS,
						GROUP_SETUP,
						GROUP_INJECT
					] },
					additionalItems: false,
					uniqueItems: true
				},
				deepData: { type: "boolean" },
				ignorePublicMembers: { type: "boolean" },
				unreferencedOptions: {
					type: "array",
					items: { enum: [UNREFERENCED_UNKNOWN_MEMBER, UNREFERENCED_RETURN] },
					additionalItems: false,
					uniqueItems: true
				}
			},
			additionalProperties: false
		}],
		messages: { unused: "'{{name}}' of {{group}} found, but never used." }
	},
	create(context) {
		const options = context.options[0] || {};
		const groups = new Set(options.groups || [GROUP_PROPERTY]);
		const shouldCheckDeepData = Boolean(options.deepData);
		const shouldIgnorePublicMembers = Boolean(options.ignorePublicMembers);
		const unreferencedOptions = new Set(options.unreferencedOptions || []);
		let propsReferencePattern = null;
		const propertyReferenceExtractor = require_property_references.definePropertyReferenceExtractor(context, {
			unknownMemberAsUnreferenced: unreferencedOptions.has(UNREFERENCED_UNKNOWN_MEMBER),
			returnAsUnreferenced: unreferencedOptions.has(UNREFERENCED_RETURN)
		});
		const templatePropertiesContainer = {
			propertyReferences: [],
			refNames: /* @__PURE__ */ new Set()
		};
		const vueComponentPropertiesContainerMap = /* @__PURE__ */ new Map();
		function getVueComponentPropertiesContainer(node) {
			let container = vueComponentPropertiesContainerMap.get(node);
			if (!container) {
				container = {
					properties: [],
					propertyReferences: [],
					propertyReferencesForProps: []
				};
				vueComponentPropertiesContainerMap.set(node, container);
			}
			return container;
		}
		function verifyDataOptionDeepProperties(segments, propertyValue, propertyReferences) {
			let targetExpr = propertyValue;
			if (targetExpr.type === "Identifier") targetExpr = findExpression(context, targetExpr);
			if (targetExpr.type === "ObjectExpression") for (const prop of targetExpr.properties) {
				if (prop.type !== "Property") continue;
				const name = import_utils.default.getStaticPropertyName(prop);
				if (name == null) continue;
				if (!propertyReferences.hasProperty(name, { unknownCallAsAny: true })) {
					context.report({
						node: prop.key,
						messageId: "unused",
						data: {
							group: PROPERTY_LABEL.data,
							name: [...segments, name].join(".")
						}
					});
					continue;
				}
				verifyDataOptionDeepProperties([...segments, name], prop.value, propertyReferences.getNest(name));
			}
		}
		/**
		* Report the given property if it is unused.
		*/
		function verifyPropertyUsage(property, propertyReferences, propertyReferencesForProps) {
			if (property.groupName === "props" && propertyReferencesForProps.hasProperty(property.name) || propertyReferences.hasProperty("$props")) return;
			if (property.groupName === "setup" && templatePropertiesContainer.refNames.has(property.name)) return;
			if (shouldIgnorePublicMembers && isPublicMember(property, context.sourceCode)) return;
			if (propertyReferences.hasProperty(property.name)) {
				if (shouldCheckDeepData && (property.groupName === "data" || property.groupName === "asyncData") && property.type === "object") verifyDataOptionDeepProperties([property.name], property.property.value, propertyReferences.getNest(property.name));
				return;
			}
			context.report({
				node: property.node,
				messageId: "unused",
				data: {
					group: PROPERTY_LABEL[property.groupName],
					name: property.name
				}
			});
		}
		/**
		* Report all unused properties.
		*/
		function reportUnusedProperties() {
			for (const container of vueComponentPropertiesContainerMap.values()) {
				const propertyReferences = require_property_references.mergePropertyReferences([...container.propertyReferences, ...templatePropertiesContainer.propertyReferences]);
				const propertyReferencesForProps = require_property_references.mergePropertyReferences(container.propertyReferencesForProps);
				for (const property of container.properties) verifyPropertyUsage(property, propertyReferences, propertyReferencesForProps);
			}
		}
		function getParentProperty(node) {
			if (!node.parent || node.parent.type !== "Property" || node.parent.value !== node) return null;
			const property = node.parent;
			if (!import_utils.default.isProperty(property)) return null;
			return property;
		}
		const scriptVisitor = import_utils.default.compositingVisitors(import_utils.default.defineScriptSetupVisitor(context, {
			onDefinePropsEnter(node, props) {
				if (!groups.has("props")) return;
				const container = getVueComponentPropertiesContainer(context.sourceCode.ast);
				for (const prop of props) {
					if (!prop.propName) continue;
					if (prop.type === "object") container.properties.push({
						type: prop.type,
						name: prop.propName,
						groupName: "props",
						node: prop.key,
						property: prop.node
					});
					else container.properties.push({
						type: prop.type,
						name: prop.propName,
						groupName: "props",
						node: prop.type === "infer-type" ? prop.node : prop.key
					});
				}
				let target = node;
				if (target.parent && target.parent.type === "CallExpression" && target.parent.arguments[0] === target && target.parent.callee.type === "Identifier" && target.parent.callee.name === "withDefaults") target = target.parent;
				if (!target.parent || target.parent.type !== "VariableDeclarator" || target.parent.init !== target) return;
				propsReferencePattern = target.parent.id;
				const propertyReferences = propertyReferenceExtractor.extractFromPattern(propsReferencePattern);
				container.propertyReferencesForProps.push(propertyReferences);
			},
			onDefineModelEnter(node, model) {
				if (!groups.has("props")) return;
				const container = getVueComponentPropertiesContainer(context.sourceCode.ast);
				if (node.parent && node.parent.type === "VariableDeclarator" && node.parent.init === node) {
					container.propertyReferences.push(propertyReferenceExtractor.extractFromName(model.name.modelName, model.name.node || node));
					return;
				}
				container.properties.push({
					type: "model",
					name: model.name.modelName,
					groupName: "props",
					node: model.name.node || node
				});
			}
		}), import_utils.default.defineVueVisitor(context, {
			CallExpression(node, vueData) {
				if (node.callee.type !== "Identifier") return;
				let groupName = null;
				if (/^mapMutations|mapActions$/u.test(node.callee.name)) groupName = "methods";
				else if (/^mapState|mapGetters|mapWritableState$/u.test(node.callee.name)) groupName = "computed";
				if (!groupName || node.arguments.length === 0) return;
				const arg = node.arguments.length === 2 ? node.arguments[1] : node.arguments[0];
				if (arg.type === "ObjectExpression") {
					const container = getVueComponentPropertiesContainer(vueData.node);
					for (const prop of arg.properties) {
						const name = prop.type === "SpreadElement" ? null : import_utils.default.getStaticPropertyName(prop);
						if (name) container.properties.push({
							type: "array",
							name,
							groupName,
							node: prop
						});
					}
				} else if (arg.type === "ArrayExpression") {
					const container = getVueComponentPropertiesContainer(vueData.node);
					for (const element of arg.elements) {
						if (!element || element.type !== "Literal" && element.type !== "TemplateLiteral") continue;
						const name = import_utils.default.getStringLiteralValue(element);
						if (name) container.properties.push({
							type: "array",
							name,
							groupName,
							node: element
						});
					}
				}
			},
			onVueObjectEnter(node, vueNode) {
				const container = getVueComponentPropertiesContainer(vueNode.node);
				const watchersAndExposes = import_utils.default.iterateProperties(node, /* @__PURE__ */ new Set([GROUP_WATCHER, GROUP_EXPOSE]));
				for (const watcherOrExpose of watchersAndExposes) if (watcherOrExpose.groupName === GROUP_WATCHER) {
					const watcher = watcherOrExpose;
					container.propertyReferences.push(propertyReferenceExtractor.extractFromPath(watcher.name, watcher.node));
					if (watcher.type === "object") {
						const property = watcher.property;
						if (property.kind === "init") for (const handlerValueNode of import_utils.default.iterateWatchHandlerValues(property)) container.propertyReferences.push(propertyReferenceExtractor.extractFromNameLiteral(handlerValueNode));
					}
				} else if (watcherOrExpose.groupName === GROUP_EXPOSE) {
					const expose = watcherOrExpose;
					container.propertyReferences.push(propertyReferenceExtractor.extractFromName(expose.name, expose.node));
				}
				container.properties.push(...import_utils.default.iterateProperties(node, groups));
			},
			"ObjectExpression > Property > :function[params.length>0]"(node, vueData) {
				const property = getParentProperty(node);
				if (!property) return;
				if (property.parent === vueData.node) {
					if (import_utils.default.getStaticPropertyName(property) !== "data") return;
				} else {
					const parentProperty = getParentProperty(property.parent);
					if (!parentProperty) return;
					if (parentProperty.parent === vueData.node) {
						if (import_utils.default.getStaticPropertyName(parentProperty) !== "computed") return;
					} else {
						const parentParentProperty = getParentProperty(parentProperty.parent);
						if (!parentParentProperty) return;
						if (parentParentProperty.parent === vueData.node) {
							if (import_utils.default.getStaticPropertyName(parentParentProperty) !== "computed" || import_utils.default.getStaticPropertyName(property) !== "get") return;
						} else return;
					}
				}
				const propertyReferences = propertyReferenceExtractor.extractFromFunctionParam(node, 0);
				getVueComponentPropertiesContainer(vueData.node).propertyReferences.push(propertyReferences);
			},
			onSetupFunctionEnter(node, vueData) {
				const container = getVueComponentPropertiesContainer(vueData.node);
				const propertyReferences = propertyReferenceExtractor.extractFromFunctionParam(node, 0);
				container.propertyReferencesForProps.push(propertyReferences);
			},
			onRenderFunctionEnter(node, vueData) {
				const container = getVueComponentPropertiesContainer(vueData.node);
				const propertyReferences = propertyReferenceExtractor.extractFromFunctionParam(node, 0);
				container.propertyReferencesForProps.push(propertyReferences);
				if (vueData.functional) {
					const propertyReferencesForV2 = propertyReferenceExtractor.extractFromFunctionParam(node, 1);
					container.propertyReferencesForProps.push(propertyReferencesForV2.getNest("props"));
				}
			},
			"ThisExpression, Identifier"(node, vueData) {
				if (!import_utils.default.isThis(node, context)) return;
				const container = getVueComponentPropertiesContainer(vueData.node);
				const propertyReferences = propertyReferenceExtractor.extractFromExpression(node, false);
				container.propertyReferences.push(propertyReferences);
			}
		}), {
			Program() {
				const styleVars = require_index$1.getStyleVariablesContext(context);
				if (styleVars) templatePropertiesContainer.propertyReferences.push(propertyReferenceExtractor.extractFromStyleVariablesContext(styleVars));
			},
			"Program:exit"(node) {
				if (!node.templateBody) reportUnusedProperties();
			}
		});
		return import_utils.default.defineTemplateBodyVisitor(context, {
			VExpressionContainer(node) {
				const property = propertyReferenceExtractor.extractFromVExpressionContainer(node);
				templatePropertiesContainer.propertyReferences.push(property);
				if (!propsReferencePattern) return;
				for (const key of property.allProperties().keys()) if (propsReferencePattern.type === "Identifier" && propsReferencePattern.name === key) templatePropertiesContainer.propertyReferences.push(property.getNest(key));
			},
			"VAttribute[directive=false]"(node) {
				if (node.key.name === "ref" && node.value != null) templatePropertiesContainer.refNames.add(node.value.value);
			},
			"VElement[parent.type!='VElement']:exit"() {
				reportUnusedProperties();
			}
		}, scriptVisitor);
	}
};
//#endregion
exports.default = no_unused_properties_default;
