import { ruleCreator } from "../_internal/rule-creator.js";
const functionLikeNodeSelector = ":matches(ArrowFunctionExpression, FunctionDeclaration, FunctionExpression, TSCallSignatureDeclaration, TSConstructSignatureDeclaration, TSConstructorType, TSDeclareFunction, TSEmptyBodyFunctionExpression, TSFunctionType, TSMethodSignature)";
const getParametersFromFunctionLikeNode = (node) => {
    if (node.type === "ArrowFunctionExpression" ||
        node.type === "FunctionDeclaration" ||
        node.type === "FunctionExpression" ||
        node.type === "TSCallSignatureDeclaration" ||
        node.type === "TSConstructSignatureDeclaration" ||
        node.type === "TSConstructorType" ||
        node.type === "TSDeclareFunction" ||
        node.type === "TSEmptyBodyFunctionExpression" ||
        node.type === "TSFunctionType" ||
        node.type === "TSMethodSignature") {
        return node.params;
    }
    return undefined;
};
const getTypeAnnotationFromPattern = (pattern) => {
    if (pattern.type === "AssignmentPattern") {
        return getTypeAnnotationFromPattern(pattern.left);
    }
    if (pattern.type === "RestElement") {
        if (pattern.typeAnnotation !== undefined) {
            return pattern.typeAnnotation;
        }
        const argument = pattern.argument;
        if (argument.type !== "ArrayPattern" &&
            argument.type !== "Identifier" &&
            argument.type !== "ObjectPattern") {
            return undefined;
        }
        return argument.typeAnnotation;
    }
    return pattern.typeAnnotation;
};
const getTypeAnnotationFromParameter = (parameter) => {
    if (parameter.type === "TSParameterProperty") {
        return getTypeAnnotationFromPattern(parameter.parameter);
    }
    return getTypeAnnotationFromPattern(parameter);
};
const isSetTypeReference = (node) => node.typeName.type === "Identifier" && node.typeName.name === "Set";
const collectMutableSetTypeNodes = (typeNode) => {
    if (typeNode.type === "TSIntersectionType" ||
        typeNode.type === "TSUnionType") {
        return typeNode.types.flatMap((subTypeNode) => collectMutableSetTypeNodes(subTypeNode));
    }
    if (typeNode.type !== "TSTypeReference" || !isSetTypeReference(typeNode)) {
        return [];
    }
    return [typeNode.typeName];
};
const buildReadonlySetFix = (node) => (fixer) => fixer.replaceText(node, "ReadonlySet");
/**
 * Require readonly set parameter type annotations.
 */
const rule = ruleCreator({
    create: (context) => ({
        [functionLikeNodeSelector]: (node) => {
            const parameters = getParametersFromFunctionLikeNode(node);
            if (parameters === undefined) {
                return;
            }
            for (const parameter of parameters) {
                const typeAnnotation = getTypeAnnotationFromParameter(parameter);
                if (typeAnnotation === undefined) {
                    continue;
                }
                const mutableSetTypeNodes = collectMutableSetTypeNodes(typeAnnotation.typeAnnotation);
                for (const mutableSetTypeNode of mutableSetTypeNodes) {
                    const fix = buildReadonlySetFix(mutableSetTypeNode);
                    context.report({
                        fix,
                        messageId: "forbidden",
                        node: mutableSetTypeNode,
                        suggest: [
                            {
                                fix,
                                messageId: "suggestRequireReadonlySetParameterType",
                            },
                        ],
                    });
                }
            }
        },
    }),
    defaultOptions: [],
    meta: {
        deprecated: false,
        docs: {
            deprecated: false,
            description: "require ReadonlySet parameter type annotations.",
            frozen: false,
            recommended: false,
            url: "https://nick2bad4u.github.io/eslint-plugin-etc-misc/docs/rules/typescript-require-readonly-set-parameter-type",
        },
        fixable: "code",
        hasSuggestions: true,
        messages: {
            forbidden: "Prefer readonly set parameter types.",
            suggestRequireReadonlySetParameterType: "Convert this parameter type to ReadonlySet.",
        },
        schema: [],
        type: "suggestion",
    },
    name: "typescript/require-readonly-set-parameter-type",
});
export default rule;
//# sourceMappingURL=typescript-require-readonly-set-parameter-type.js.map