UNPKG

eslint-plugin-functional

Version:
4,948 lines 163 kB
import { deepmerge } from 'deepmerge-ts';
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
import { RuleCreator, getParserServices } from '@typescript-eslint/utils/eslint-utils';
import { createRequire } from 'node:module';
import { Immutability, getDefaultOverrides, getTypeImmutability } from 'is-immutable-type';
import { isIntrinsicErrorType } from 'ts-api-utils';
import typeMatchesSpecifier from 'ts-declaration-location';
import escapeRegExp from 'escape-string-regexp';

const require$1 = createRequire(import.meta.url);
const typescript = (() => {
    try {
        return require$1("typescript");
    }
    catch {
        return undefined;
    }
})();
// export default (await import("typescript")
//   .then((r) => r.default)
//   .catch(() => undefined)) as typeof typescript | undefined;

/**
 * The settings that have been loaded - so we don't have to reload them.
 */
const cachedSettings = new WeakMap();
/**
 * Get the immutability overrides defined in the settings.
 */
function getImmutabilityOverrides({ immutability, }) {
    if (immutability === undefined) {
        return undefined;
    }
    if (!cachedSettings.has(immutability)) {
        const overrides = loadImmutabilityOverrides(immutability);
        cachedSettings.set(immutability, overrides);
        return overrides;
    }
    return cachedSettings.get(immutability);
}
/**
 * Get all the overrides and upgrade them.
 */
function loadImmutabilityOverrides(immutabilitySettings) {
    const overridesSetting = immutabilitySettings?.overrides;
    if (overridesSetting === undefined) {
        return undefined;
    }
    const raw = Array.isArray(overridesSetting) ? overridesSetting : (overridesSetting.values ?? []);
    const upgraded = raw.map((rawValue) => {
        const { type, to, from, ...rest } = rawValue;
        const value = {
            type,
            to: typeof to === "string" ? Immutability[to] : to,
            from: from === undefined ? undefined : typeof from === "string" ? Immutability[from] : from,
        };
        if (value.type === undefined) {
            throw new Error(`Override is missing required "type" property. Value: "${JSON.stringify(rawValue)}"`);
        }
        if (value.to === undefined) {
            throw new Error(`Override is missing required "to" property. Value: "${JSON.stringify(rawValue)}"`);
        }
        const restKeys = Object.keys(rest);
        if (restKeys.length > 0) {
            throw new Error(`Override is contains unknown property(s) "${restKeys.join(", ")}". Value: "${JSON.stringify(rawValue)}"`);
        }
        return value;
    });
    const keepDefault = Array.isArray(overridesSetting) || overridesSetting.keepDefault !== false;
    return keepDefault ? [...getDefaultOverrides(), ...upgraded] : upgraded;
}

// eslint-disable-next-line ts/naming-convention -- This is a special var.
const __VERSION__ = "9.0.1";

function typeMatchesPattern(program, type, typeNode, include, exclude = []) {
    if (include.length === 0) {
        return false;
    }
    let mut_shouldInclude = false;
    const typeNameAlias = getTypeAliasName(type, typeNode);
    if (typeNameAlias !== null) {
        const testTypeNameAlias = (pattern) => typeof pattern === "string" ? pattern === typeNameAlias : pattern.test(typeNameAlias);
        if (exclude.some(testTypeNameAlias)) {
            return false;
        }
        mut_shouldInclude ||= include.some(testTypeNameAlias);
    }
    const typeValue = getTypeAsString(program, type, typeNode);
    const testTypeValue = (pattern) => typeof pattern === "string" ? pattern === typeValue : pattern.test(typeValue);
    if (exclude.some(testTypeValue)) {
        return false;
    }
    mut_shouldInclude ||= include.some(testTypeValue);
    const typeNameName = extractTypeName(typeValue);
    if (typeNameName !== null) {
        const testTypeNameName = (pattern) => typeof pattern === "string" ? pattern === typeNameName : pattern.test(typeNameName);
        if (exclude.some(testTypeNameName)) {
            return false;
        }
        mut_shouldInclude ||= include.some(testTypeNameName);
    }
    // Special handling for arrays not written in generic syntax.
    if (program.getTypeChecker().isArrayType(type) && typeNode !== null) {
        if ((typescript.isTypeOperatorNode(typeNode) && typeNode.operator === typescript.SyntaxKind.ReadonlyKeyword) ||
            (typescript.isTypeOperatorNode(typeNode.parent) && typeNode.parent.operator === typescript.SyntaxKind.ReadonlyKeyword)) {
            const testIsReadonlyArray = (pattern) => typeof pattern === "string" && pattern === "ReadonlyArray";
            if (exclude.some(testIsReadonlyArray)) {
                return false;
            }
            mut_shouldInclude ||= include.some(testIsReadonlyArray);
        }
        else {
            const testIsArray = (pattern) => typeof pattern === "string" && pattern === "Array";
            if (exclude.some(testIsArray)) {
                return false;
            }
            mut_shouldInclude ||= include.some(testIsArray);
        }
    }
    return mut_shouldInclude;
}
/**
 * Get the type alias name from the given type data.
 *
 * Null will be returned if the type is not a type alias.
 */
function getTypeAliasName(type, typeNode) {
    if (typeNode === null) {
        const t = "target" in type ? type.target : type;
        return t.aliasSymbol?.getName() ?? null;
    }
    return typescript.isTypeAliasDeclaration(typeNode.parent) ? typeNode.parent.name.getText() : null;
}
/**
 * Get the type as a string.
 */
function getTypeAsString(program, type, typeNode) {
    return typeNode === null
        ? program
            .getTypeChecker()
            .typeToString(type, undefined, typescript.TypeFormatFlags.AddUndefined |
            typescript.TypeFormatFlags.NoTruncation |
            typescript.TypeFormatFlags.OmitParameterModifiers |
            typescript.TypeFormatFlags.UseFullyQualifiedType |
            typescript.TypeFormatFlags.WriteArrayAsGenericType |
            typescript.TypeFormatFlags.WriteArrowStyleSignature |
            typescript.TypeFormatFlags.WriteTypeArgumentsOfSignature)
        : typeNode.getText();
}
/**
 * Get the type name extracted from the the type's string.
 *
 * This only work if the type is a type reference.
 */
function extractTypeName(typeValue) {
    const match = /^([^<]+)<.+>$/u.exec(typeValue);
    return match?.[1] ?? null;
}

/**
 * Create a function that processes common options and then runs the given
 * check.
 */
function checkNode(check, context, options) {
    return (node) => {
        const result = check(node, context, options);
        // eslint-disable-next-line functional/no-loop-statements -- can't really be avoided.
        for (const descriptor of result.descriptors) {
            result.context.report(descriptor);
        }
    };
}
/**
 * Create a rule.
 */
function createRule(name, meta, defaultOptions, ruleFunctionsMap) {
    return createRuleUsingFunction(name, meta, defaultOptions, () => ruleFunctionsMap);
}
/**
 * Create a rule.
 */
function createRuleUsingFunction(name, meta, defaultOptions, createFunction) {
    const ruleCreator = RuleCreator((ruleName) => `https://github.com/eslint-functional/eslint-plugin-functional/blob/v${__VERSION__}/docs/rules/${ruleName}.md`);
    return ruleCreator({
        name,
        meta,
        defaultOptions,
        create: (context, options) => {
            const ruleFunctionsMap = createFunction(context, options);
            return Object.fromEntries(Object.entries(ruleFunctionsMap).map(([nodeSelector, ruleFunction]) => [
                nodeSelector,
                checkNode(ruleFunction, context, options),
            ]));
        },
    });
}
/**
 * Get the type of the the given node.
 */
function getTypeOfNode(node, context) {
    const { esTreeNodeToTSNodeMap } = getParserServices(context);
    const tsNode = esTreeNodeToTSNodeMap.get(node);
    return getTypeOfTSNode(tsNode, context);
}
/**
 * Get the type of the the given node.
 */
function getTypeDataOfNode(node, context) {
    const { esTreeNodeToTSNodeMap } = getParserServices(context);
    const tsNode = esTreeNodeToTSNodeMap.get(node);
    return [getTypeOfTSNode(tsNode, context), tsNode.type ?? null];
}
/**
 * Get the type of the the given ts node.
 */
function getTypeOfTSNode(node, context) {
    const { program } = getParserServices(context);
    const checker = program.getTypeChecker();
    const nodeType = checker.getTypeAtLocation(node);
    const constrained = checker.getBaseConstraintOfType(nodeType);
    return constrained ?? nodeType;
}
/**
 * Get the return type of the the given function node.
 */
function getReturnTypesOfFunction(node, context) {
    if (typescript === undefined) {
        return null;
    }
    const parserServices = getParserServices(context);
    const checker = parserServices.program.getTypeChecker();
    const type = getTypeOfNode(node, context);
    const signatures = checker.getSignaturesOfType(type, typescript.SignatureKind.Call);
    return signatures.map((signature) => checker.getReturnTypeOfSignature(signature));
}
/**
 * Does the given function have overloads?
 */
function isImplementationOfOverload(func, context) {
    if (typescript === undefined) {
        return false;
    }
    const parserServices = getParserServices(context);
    const checker = parserServices.program.getTypeChecker();
    const signature = parserServices.esTreeNodeToTSNodeMap.get(func);
    return checker.isImplementationOfOverload(signature) === true;
}
/**
 * Get the type immutability of the the given node or type.
 */
function getTypeImmutabilityOfNode(node, context, maxImmutability, explicitOverrides) {
    if (typescript === undefined) {
        return Immutability.Unknown;
    }
    const parserServices = getParserServices(context);
    const overrides = getImmutabilityOverrides(context.settings);
    const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node);
    let mut_typeLike = tsNode.type;
    if (mut_typeLike === undefined) {
        mut_typeLike = getTypeOfTSNode(tsNode, context);
        if (isIntrinsicErrorType(mut_typeLike)) {
            return Immutability.Unknown;
        }
    }
    return getTypeImmutability(parserServices.program, mut_typeLike, overrides, 
    // Don't use the global cache in testing environments as it may cause errors when switching between different config options.
    process.env["NODE_ENV"] !== "test", maxImmutability, typeMatchesPattern);
}
/**
 * Get the type immutability of the the given type.
 */
function getTypeImmutabilityOfType(typeOrTypeNode, context, maxImmutability, explicitOverrides) {
    const parserServices = getParserServices(context);
    const overrides = getImmutabilityOverrides(context.settings);
    return getTypeImmutability(parserServices.program, typeOrTypeNode, overrides, 
    // Don't use the global cache in testing environments as it may cause errors when switching between different config options.
    process.env["NODE_ENV"] !== "test", maxImmutability);
}

/**
 * @file Functions that type guard the given node/type.
 */
const libSpecifier = {
    from: "lib",
};
/*
 * Node type guards.
 */
function isArrayExpression(node) {
    return node.type === AST_NODE_TYPES.ArrayExpression;
}
function isArrayPattern(node) {
    return node.type === AST_NODE_TYPES.ArrayPattern;
}
function isAssignmentExpression(node) {
    return node.type === AST_NODE_TYPES.AssignmentExpression;
}
function isAssignmentPattern(node) {
    return node.type === AST_NODE_TYPES.AssignmentPattern;
}
function isBlockStatement(node) {
    return node.type === AST_NODE_TYPES.BlockStatement;
}
function isBreakStatement(node) {
    return node.type === AST_NODE_TYPES.BreakStatement;
}
function isCallExpression(node) {
    return node.type === AST_NODE_TYPES.CallExpression;
}
function isChainExpression(node) {
    return node.type === AST_NODE_TYPES.ChainExpression;
}
function isPropertyDefinition(node) {
    return node.type === AST_NODE_TYPES.PropertyDefinition;
}
/**
 * Is the given node a class node?
 *
 * It doesn't matter what type of class.
 */
function isClassLike(node) {
    return node.type === AST_NODE_TYPES.ClassDeclaration || node.type === AST_NODE_TYPES.ClassExpression;
}
function isContinueStatement(node) {
    return node.type === AST_NODE_TYPES.ContinueStatement;
}
function isExpressionStatement(node) {
    return node.type === AST_NODE_TYPES.ExpressionStatement;
}
function isForStatement(node) {
    return node.type === AST_NODE_TYPES.ForStatement;
}
function isFunctionDeclaration(node) {
    return node.type === AST_NODE_TYPES.FunctionDeclaration;
}
/**
 * Is the given node a function expression node?
 *
 * It doesn't matter what type of function expression.
 */
function isFunctionExpressionLike(node) {
    return node.type === AST_NODE_TYPES.FunctionExpression || node.type === AST_NODE_TYPES.ArrowFunctionExpression;
}
/**
 * Is the given node a function node?
 *
 * It doesn't matter what type of function.
 */
function isFunctionLike(node) {
    return isFunctionDeclaration(node) || isFunctionExpressionLike(node);
}
function isIdentifier(node) {
    return node.type === AST_NODE_TYPES.Identifier;
}
function isIfStatement(node) {
    return node.type === AST_NODE_TYPES.IfStatement;
}
function isLabeledStatement(node) {
    return node.type === AST_NODE_TYPES.LabeledStatement;
}
function isMemberExpression(node) {
    return node.type === AST_NODE_TYPES.MemberExpression;
}
function isMethodDefinition(node) {
    return node.type === AST_NODE_TYPES.MethodDefinition;
}
function isNewExpression(node) {
    return node.type === AST_NODE_TYPES.NewExpression;
}
function isObjectExpression(node) {
    return node.type === AST_NODE_TYPES.ObjectExpression;
}
function isObjectPattern(node) {
    return node.type === AST_NODE_TYPES.ObjectPattern;
}
function isPrivateIdentifier(node) {
    return node.type === AST_NODE_TYPES.PrivateIdentifier;
}
function isProgram(node) {
    return node.type === AST_NODE_TYPES.Program;
}
function isProperty(node) {
    return node.type === AST_NODE_TYPES.Property;
}
function isRestElement(node) {
    return node.type === AST_NODE_TYPES.RestElement;
}
function isReturnStatement(node) {
    return node.type === AST_NODE_TYPES.ReturnStatement;
}
function isSwitchStatement(node) {
    return node.type === AST_NODE_TYPES.SwitchStatement;
}
function isThisExpression(node) {
    return node.type === AST_NODE_TYPES.ThisExpression;
}
function isThrowStatement(node) {
    return node.type === AST_NODE_TYPES.ThrowStatement;
}
function isTryStatement(node) {
    return node.type === AST_NODE_TYPES.TryStatement;
}
function isTSArrayType(node) {
    return node.type === AST_NODE_TYPES.TSArrayType;
}
function isTSAsExpression(node) {
    return node.type === AST_NODE_TYPES.TSAsExpression;
}
function isTSFunctionType(node) {
    return node.type === AST_NODE_TYPES.TSFunctionType;
}
function isTSIndexSignature(node) {
    return node.type === AST_NODE_TYPES.TSIndexSignature;
}
function isTSMethodSignature(node) {
    return node.type === AST_NODE_TYPES.TSMethodSignature;
}
function isTSCallSignatureDeclaration(node) {
    return node.type === AST_NODE_TYPES.TSCallSignatureDeclaration;
}
function isTSConstructSignatureDeclaration(node) {
    return node.type === AST_NODE_TYPES.TSConstructSignatureDeclaration;
}
function isTSInterfaceBody(node) {
    return node.type === AST_NODE_TYPES.TSInterfaceBody;
}
function isTSInterfaceDeclaration(node) {
    return node.type === AST_NODE_TYPES.TSInterfaceDeclaration;
}
function isTSInterfaceHeritage(node) {
    return node.type === AST_NODE_TYPES.TSInterfaceHeritage;
}
function isTSNonNullExpression(node) {
    return node.type === AST_NODE_TYPES.TSNonNullExpression;
}
function isTSNullKeyword(node) {
    return node.type === AST_NODE_TYPES.TSNullKeyword;
}
function isTSParameterProperty(node) {
    return node.type === AST_NODE_TYPES.TSParameterProperty;
}
function isTSPropertySignature(node) {
    return node.type === AST_NODE_TYPES.TSPropertySignature;
}
function isTSTupleType(node) {
    return node.type === AST_NODE_TYPES.TSTupleType;
}
function isTSTypeAnnotation(node) {
    return node.type === AST_NODE_TYPES.TSTypeAnnotation;
}
function isTSTypeLiteral(node) {
    return node.type === AST_NODE_TYPES.TSTypeLiteral;
}
function isTSTypeOperator(node) {
    return node.type === AST_NODE_TYPES.TSTypeOperator;
}
function isTSTypePredicate(node) {
    return node.type === AST_NODE_TYPES.TSTypePredicate;
}
function isTSTypeReference(node) {
    return node.type === AST_NODE_TYPES.TSTypeReference;
}
function isTSUndefinedKeyword(node) {
    return node.type === AST_NODE_TYPES.TSUndefinedKeyword;
}
function isTSVoidKeyword(node) {
    return node.type === AST_NODE_TYPES.TSVoidKeyword;
}
function isUnaryExpression(node) {
    return node.type === AST_NODE_TYPES.UnaryExpression;
}
function isVariableDeclaration(node) {
    return node.type === AST_NODE_TYPES.VariableDeclaration;
}
function isYieldExpression(node) {
    return node.type === AST_NODE_TYPES.YieldExpression;
}
function hasID(node) {
    return Object.hasOwn(node, "id");
}
function hasKey(node) {
    return Object.hasOwn(node, "key");
}
function isDefined(value) {
    return value !== null && value !== undefined;
}
/*
 * TS types type guards.
 */
function isUnionType(type) {
    return typescript !== undefined && type.flags === typescript.TypeFlags.Union;
}
function isFunctionLikeType(type) {
    return type !== null && type.getCallSignatures().length > 0;
}
function isArrayType(context, type) {
    return typeMatches(context, "Array", type);
}
function isMapType(context, type) {
    return typeMatches(context, "Map", type);
}
function isSetType(context, type) {
    return typeMatches(context, "Set", type);
}
function isArrayConstructorType(context, type) {
    return typeMatches(context, "ArrayConstructor", type);
}
function isMapConstructorType(context, type) {
    return typeMatches(context, "MapConstructor", type);
}
function isSetConstructorType(context, type) {
    return typeMatches(context, "SetConstructor", type);
}
function isObjectConstructorType(context, type) {
    return typeMatches(context, "ObjectConstructor", type);
}
function isPromiseType(context, type) {
    return typeMatches(context, "Promise", type);
}
function typeMatches(context, typeName, type) {
    if (type === null) {
        return false;
    }
    const program = context.sourceCode.parserServices?.program ?? undefined;
    if (program === undefined) {
        return false;
    }
    return typeMatchesHelper(program, typeName)(type);
}
function typeMatchesHelper(program, typeName) {
    return function test(type) {
        return ((type.symbol !== undefined &&
            type.symbol.name === typeName &&
            typeMatchesSpecifier(program, libSpecifier, type)) ||
            (isUnionType(type) && type.types.some(test)));
    };
}

/**
 * Return the first ancestor that meets the given check criteria.
 */
function getAncestorOfType(checker, node, child = null) {
    return checker(node, child) ? node : isDefined(node.parent) ? getAncestorOfType(checker, node.parent, node) : null;
}
/**
 * Test if the given node is in a function's body.
 *
 * @param node - The node to test.
 * @param async - Whether the function must be async or sync. Use `undefined` for either.
 */
function isInFunctionBody(node, async) {
    const functionNode = getEnclosingFunction(node);
    return functionNode !== null && (async === undefined);
}
/**
 * Get the function the given node is in.
 *
 * Will return null if not in a function.
 */
function getEnclosingFunction(node) {
    return getAncestorOfType((n, c) => isFunctionLike(n) && n.body === c, node);
}
/**
 * Get the function the given node is in.
 *
 * Will return null if not in a function.
 */
function getEnclosingTryStatement(node) {
    return getAncestorOfType((n, c) => isTryStatement(n) && n.block === c, node);
}
/**
 * Test if the given node is in a class.
 */
function isInClass(node) {
    return getAncestorOfType(isClassLike, node) !== null;
}
/**
 * Test if the given node is in a for loop initializer.
 */
function isInForLoopInitializer(node) {
    return getAncestorOfType((n, c) => isForStatement(n) && n.init === c, node) !== null;
}
/**
 * Test if the given node is shallowly inside a `Readonly<{...}>`.
 */
function isInReadonly(node) {
    return getReadonly(node) !== null;
}
/**
 * Test if the given node is in a handler function callback of a promise.
 */
function isInPromiseHandlerFunction(node, context) {
    const functionNode = getAncestorOfType((n, c) => isFunctionLike(n) && n.body === c, node);
    if (functionNode === null ||
        !isCallExpression(functionNode.parent) ||
        !isMemberExpression(functionNode.parent.callee) ||
        !isIdentifier(functionNode.parent.callee.property)) {
        return false;
    }
    const objectType = getTypeOfNode(functionNode.parent.callee.object, context);
    return isPromiseType(context, objectType);
}
/**
 * Test if the given node is shallowly inside a `Readonly<{...}>`.
 */
function getReadonly(node) {
    // For nested cases, we shouldn't look for any parent, but the immediate parent.
    if (isDefined(node.parent) &&
        isTSTypeLiteral(node.parent) &&
        isDefined(node.parent.parent) &&
        isTSTypeAnnotation(node.parent.parent)) {
        return null;
    }
    const typeRef = getAncestorOfType(isTSTypeReference, node);
    const intHeritage = getAncestorOfType(isTSInterfaceHeritage, node);
    const expressionOrTypeName = typeRef?.typeName ?? intHeritage?.expression;
    return expressionOrTypeName !== undefined &&
        isIdentifier(expressionOrTypeName) &&
        expressionOrTypeName.name === "Readonly"
        ? (typeRef ?? intHeritage)
        : null;
}
/**
 * Test if the given node is in a TS Property Signature.
 */
function isInInterface(node) {
    return getAncestorOfType(isTSInterfaceBody, node) !== null;
}
/**
 * Test if the given node is in a Constructor.
 */
function isInConstructor(node) {
    const methodDefinition = getAncestorOfType(isMethodDefinition, node);
    return methodDefinition !== null && isIdentifier(methodDefinition.key) && methodDefinition.key.name === "constructor";
}
/**
 * Is the given node in the return type.
 */
function isInReturnType(node) {
    return (getAncestorOfType((n) => isDefined(n.parent) && isFunctionLike(n.parent) && n.parent.returnType === n, node) !== null);
}
/**
 * Test if the given node is nested inside another statement.
 */
function isNested(node) {
    return node.parent !== undefined && !(isProgram(node.parent) || isBlockStatement(node.parent));
}
/**
 * Is the given identifier a property of an object?
 */
function isPropertyAccess(node) {
    return node.parent !== undefined && isMemberExpression(node.parent) && node.parent.property === node;
}
/**
 * Is the given identifier a property name?
 */
function isPropertyName(node) {
    return node.parent !== undefined && isProperty(node.parent) && node.parent.key === node;
}
/**
 * Is the given function an IIFE?
 */
function isIIFE(node) {
    return (isFunctionExpressionLike(node) &&
        node.parent !== undefined &&
        isCallExpression(node.parent) &&
        node.parent.callee === node);
}
/**
 * Is the given node being passed as an argument?
 */
function isArgument(node) {
    return node.parent !== undefined && isCallExpression(node.parent) && node.parent.arguments.includes(node);
}
/**
 * Is the given node a parameter?
 */
function isParameter(node) {
    return node.parent !== undefined && isFunctionLike(node.parent) && node.parent.params.includes(node);
}
/**
 * Is the given node a getter function?
 */
function isGetter(node) {
    return node.parent !== undefined && isProperty(node.parent) && node.parent.kind === "get";
}
/**
 * Is the given node a setter function?
 */
function isSetter(node) {
    return node.parent !== undefined && isProperty(node.parent) && node.parent.kind === "set";
}
/**
 * Get the key the given node is assigned to in its parent ObjectExpression.
 */
function getKeyOfValueInObjectExpression(node) {
    if (!isDefined(node.parent)) {
        return null;
    }
    const objectExpression = getAncestorOfType(isObjectExpression, node);
    if (objectExpression === null) {
        return null;
    }
    const objectExpressionProps = objectExpression.properties.filter((prop) => isProperty(prop) && prop.value === node);
    if (objectExpressionProps.length !== 1) {
        return null;
    }
    const objectExpressionProp = objectExpressionProps[0];
    if (!isProperty(objectExpressionProp) || !isIdentifier(objectExpressionProp.key)) {
        return null;
    }
    return objectExpressionProp.key.name;
}
/**
 * Is the given identifier defined by a mutable variable (let or var)?
 */
function isDefinedByMutableVariable(node, context, treatParametersAsMutable) {
    const services = getParserServices(context);
    const symbol = services.getSymbolAtLocation(node);
    const variableDeclaration = symbol?.valueDeclaration;
    if (variableDeclaration === undefined) {
        return true;
    }
    const variableDeclarationNode = services.tsNodeToESTreeNodeMap.get(variableDeclaration);
    if (variableDeclarationNode !== undefined && isParameter(variableDeclarationNode)) {
        return treatParametersAsMutable(variableDeclarationNode);
    }
    if (!typescript.isVariableDeclaration(variableDeclaration)) {
        return true;
    }
    const variableDeclarator = services.tsNodeToESTreeNodeMap.get(variableDeclaration);
    if (variableDeclarator?.parent === undefined || !isVariableDeclaration(variableDeclarator.parent)) {
        return true;
    }
    return variableDeclarator.parent.kind !== "const";
}
/**
 * Get the root identifier of an expression.
 */
function findRootIdentifier(node) {
    if (isIdentifier(node)) {
        return node;
    }
    if (isMemberExpression(node)) {
        return findRootIdentifier(node.object);
    }
    return undefined;
}

const ruleNameScope = "functional";
/**
 * Does the given ExpressionStatement specify directive prologues.
 */
function isDirectivePrologue(node) {
    return (node.expression.type === AST_NODE_TYPES.Literal &&
        typeof node.expression.value === "string" &&
        node.expression.value.startsWith("use "));
}
/**
 * Get the identifier text of the given node.
 */
function getNodeIdentifierText(node, context) {
    if (!isDefined(node)) {
        return undefined;
    }
    let mut_identifierText = null;
    if (isIdentifier(node)) {
        mut_identifierText = node.name;
    }
    else if (isPrivateIdentifier(node)) {
        mut_identifierText = `#${node.name}`;
    }
    else if (hasID(node) && isDefined(node.id)) {
        mut_identifierText = getNodeIdentifierText(node.id, context);
    }
    else if (hasKey(node) && isDefined(node.key)) {
        mut_identifierText = getNodeIdentifierText(node.key, context);
    }
    else if (isAssignmentExpression(node)) {
        mut_identifierText = getNodeIdentifierText(node.left, context);
    }
    else if (isMemberExpression(node)) {
        mut_identifierText = `${getNodeIdentifierText(node.object, context)}.${getNodeIdentifierText(node.property, context)}`;
    }
    else if (isThisExpression(node)) {
        mut_identifierText = "this";
    }
    else if (isUnaryExpression(node)) {
        mut_identifierText = getNodeIdentifierText(node.argument, context);
    }
    else if (isTSTypeAnnotation(node)) {
        mut_identifierText = context.sourceCode.getText(node.typeAnnotation).replaceAll(/\s+/gu, "");
    }
    else if (isTSAsExpression(node) || isTSNonNullExpression(node) || isChainExpression(node)) {
        mut_identifierText = getNodeIdentifierText(node.expression, context);
    }
    if (mut_identifierText !== null) {
        return mut_identifierText;
    }
    const keyInObjectExpression = getKeyOfValueInObjectExpression(node);
    if (keyInObjectExpression !== null) {
        return keyInObjectExpression;
    }
    return undefined;
}
/**
 * Get the code of the given node.
 */
function getNodeCode(node, context) {
    return context.sourceCode.getText(node);
}
/**
 * Get all the identifier texts of the given node.
 */
function getNodeIdentifierTexts(node, context) {
    return (isVariableDeclaration(node)
        ? node.declarations.flatMap((declarator) => getNodeIdentifierText(declarator, context))
        : [getNodeIdentifierText(node, context)]).filter((text) => text !== undefined);
}

/**
 * The schema for the option to ignore patterns.
 */
const ignoreIdentifierPatternOptionSchema = {
    ignoreIdentifierPattern: {
        type: ["string", "array"],
        items: {
            type: "string",
        },
    },
};
/**
 * The schema for the option to ignore patterns.
 */
const ignoreCodePatternOptionSchema = {
    ignoreCodePattern: {
        type: ["string", "array"],
        items: {
            type: "string",
        },
    },
};
/**
 * The schema for the option to ignore accessor patterns.
 */
const ignoreAccessorPatternOptionSchema = {
    ignoreAccessorPattern: {
        type: ["string", "array"],
        items: {
            type: "string",
        },
    },
};
/**
 * The schema for the option to ignore classes.
 */
const ignoreClassesOptionSchema = {
    ignoreClasses: {
        oneOf: [
            {
                type: "boolean",
            },
            {
                type: "string",
                enum: ["fieldsOnly"],
            },
        ],
    },
};
/**
 * The schema for the option to ignore maps and sets.
 */
const ignoreMapsAndSetsOptionSchema = {
    ignoreMapsAndSets: {
        type: "boolean",
    },
};
/**
 * The schema for the option to ignore prefix selector.
 */
const ignorePrefixSelectorOptionSchema = {
    ignorePrefixSelector: {
        type: ["string", "array"],
        items: {
            type: "string",
        },
    },
};
/**
 * Should the given text be allowed?
 *
 * Test using the given pattern(s).
 */
function shouldIgnoreViaPattern(text, pattern) {
    const patterns = Array.isArray(pattern) ? pattern : [pattern];
    // One or more patterns match?
    return patterns.some((p) => new RegExp(p, "u").test(text));
}
/**
 * Recursive callback of `shouldIgnoreViaAccessorPattern`.
 *
 * This function not be called from anywhere else.
 *
 * Does the given text match the given pattern.
 */
function accessorPatternMatch([pattern, ...remainingPatternParts], textParts, allowExtra = false) {
    return pattern === undefined
        ? allowExtra || textParts.length === 0
        : // Match any depth (including 0)?
            pattern === "**"
                ? textParts.length === 0
                    ? accessorPatternMatch(remainingPatternParts, [], allowExtra)
                    : Array.from({ length: textParts.length })
                        .map((element, index) => index)
                        .some((offset) => accessorPatternMatch(remainingPatternParts, textParts.slice(offset), true))
                : // Match anything?
                    pattern === "*"
                        ? textParts.length > 0 && accessorPatternMatch(remainingPatternParts, textParts.slice(1), allowExtra)
                        : // Text matches pattern?
                            new RegExp(`^${escapeRegExp(pattern).replaceAll("\\*", ".*")}$`, "u").test(textParts[0]) &&
                                accessorPatternMatch(remainingPatternParts, textParts.slice(1), allowExtra);
}
/**
 * Should the given text be allowed?
 *
 * Test using the given accessor pattern(s).
 */
function shouldIgnoreViaAccessorPattern(text, pattern) {
    const patterns = Array.isArray(pattern) ? pattern : [pattern];
    // One or more patterns match?
    return patterns.some((p) => accessorPatternMatch(p.split("."), text.split(".")));
}
/**
 * Should the given node be allowed base off the following rule options?
 *
 * - AllowInFunctionOption.
 */
function shouldIgnoreInFunction(node, context, allowInFunction) {
    return allowInFunction === true && isInFunctionBody(node);
}
/**
 * Should the given node be allowed base off the following rule options?
 *
 * - IgnoreClassesOption.
 */
function shouldIgnoreClasses(node, context, ignoreClasses) {
    return ((ignoreClasses === true && (isClassLike(node) || isInClass(node))) ||
        (ignoreClasses === "fieldsOnly" &&
            (isPropertyDefinition(node) ||
                (isAssignmentExpression(node) &&
                    isInClass(node) &&
                    isMemberExpression(node.left) &&
                    isThisExpression(node.left.object)))));
}
/**
 * Should the given node be allowed base off the following rule options?
 *
 * - IgnoreAccessorPatternOption.
 * - IgnoreIdentifierPatternOption.
 */
function shouldIgnorePattern(node, context, ignoreIdentifierPattern, ignoreAccessorPattern, ignoreCodePattern) {
    const texts = getNodeIdentifierTexts(node, context);
    if (texts.length === 0) {
        return ignoreCodePattern !== undefined && shouldIgnoreViaPattern(getNodeCode(node, context), ignoreCodePattern);
    }
    return (
    // Ignore if ignoreIdentifierPattern is set and a pattern matches.
    (ignoreIdentifierPattern !== undefined &&
        texts.every((text) => shouldIgnoreViaPattern(text, ignoreIdentifierPattern))) ||
        // Ignore if ignoreAccessorPattern is set and an accessor pattern matches.
        (ignoreAccessorPattern !== undefined &&
            texts.every((text) => shouldIgnoreViaAccessorPattern(text, ignoreAccessorPattern))) ||
        // Ignore if ignoreCodePattern is set and a code pattern matches.
        (ignoreCodePattern !== undefined && shouldIgnoreViaPattern(getNodeCode(node, context), ignoreCodePattern)));
}

function upgradeRawOverridableOptions(raw) {
    return {
        ...raw,
        overrides: raw.overrides?.map((override) => ({
            ...override,
            specifiers: override.specifiers === undefined
                ? []
                : Array.isArray(override.specifiers)
                    ? override.specifiers.map(upgradeRawTypeSpecifier)
                    : [upgradeRawTypeSpecifier(override.specifiers)],
        })) ?? [],
    };
}
function upgradeRawTypeSpecifier(raw) {
    const { ignoreName, ignorePattern, name, pattern, ...rest } = raw;
    const names = name === undefined ? [] : Array.isArray(name) ? name : [name];
    const patterns = (pattern === undefined ? [] : Array.isArray(pattern) ? pattern : [pattern]).map((p) => new RegExp(p, "u"));
    const ignoreNames = ignoreName === undefined ? [] : Array.isArray(ignoreName) ? ignoreName : [ignoreName];
    const ignorePatterns = (ignorePattern === undefined ? [] : Array.isArray(ignorePattern) ? ignorePattern : [ignorePattern]).map((p) => new RegExp(p, "u"));
    const include = [...names, ...patterns];
    const exclude = [...ignoreNames, ...ignorePatterns];
    return {
        ...rest,
        include,
        exclude,
    };
}
/**
 * Get the core options to use, taking into account overrides.
 */
function getCoreOptions(node, context, options) {
    const program = context.sourceCode.parserServices?.program ?? undefined;
    if (program === undefined) {
        return options;
    }
    const [type, typeNode] = getTypeDataOfNode(node, context);
    return getCoreOptionsForType(type, typeNode, context, options);
}
function getCoreOptionsForType(type, typeNode, context, options) {
    const program = context.sourceCode.parserServices?.program ?? undefined;
    if (program === undefined) {
        return options;
    }
    const found = options.overrides?.find((override) => (Array.isArray(override.specifiers) ? override.specifiers : [override.specifiers]).some((specifier) => typeMatchesSpecifierDeep(program, specifier, type) &&
        (specifier.include === undefined ||
            specifier.include.length === 0 ||
            typeMatchesPattern(program, type, typeNode, specifier.include, specifier.exclude))));
    if (found !== undefined) {
        if (found.disable === true) {
            return null;
        }
        if (found.inherit !== false) {
            return deepmerge(options, found.options);
        }
        return found.options;
    }
    return options;
}
function typeMatchesSpecifierDeep(program, specifier, type) {
    const mut_stack = [type];
    // eslint-disable-next-line functional/no-loop-statements -- best to do this iteratively.
    while (mut_stack.length > 0) {
        const t = mut_stack.pop();
        if (typeMatchesSpecifier(program, specifier, t)) {
            return true;
        }
        if (t.aliasTypeArguments !== undefined) {
            mut_stack.push(...t.aliasTypeArguments);
        }
    }
    return false;
}

const typeSpecifierPatternSchemaProperties = {
    name: schemaInstanceOrInstanceArray({
        type: "string",
    }),
    pattern: schemaInstanceOrInstanceArray({
        type: "string",
    }),
    ignoreName: schemaInstanceOrInstanceArray({
        type: "string",
    }),
    ignorePattern: schemaInstanceOrInstanceArray({
        type: "string",
    }),
};
const typeSpecifierSchema = {
    oneOf: [
        {
            type: "object",
            properties: {
                ...typeSpecifierPatternSchemaProperties,
                from: {
                    type: "string",
                    enum: ["file"],
                },
                path: {
                    type: "string",
                },
            },
            additionalProperties: false,
        },
        {
            type: "object",
            properties: {
                ...typeSpecifierPatternSchemaProperties,
                from: {
                    type: "string",
                    enum: ["lib"],
                },
            },
            additionalProperties: false,
        },
        {
            type: "object",
            properties: {
                ...typeSpecifierPatternSchemaProperties,
                from: {
                    type: "string",
                    enum: ["package"],
                },
                package: {
                    type: "string",
                },
            },
            additionalProperties: false,
        },
    ],
};
function schemaInstanceOrInstanceArray(items) {
    return {
        oneOf: [
            items,
            {
                type: "array",
                items,
            },
        ],
    };
}
function overridableOptionsSchema(coreOptionsPropertiesSchema) {
    return {
        type: "object",
        properties: deepmerge(coreOptionsPropertiesSchema, {
            overrides: {
                type: "array",
                items: {
                    type: "object",
                    properties: {
                        specifiers: schemaInstanceOrInstanceArray(typeSpecifierSchema),
                        options: {
                            type: "object",
                            properties: coreOptionsPropertiesSchema,
                            additionalProperties: false,
                        },
                        inherit: {
                            type: "boolean",
                        },
                        disable: {
                            type: "boolean",
                        },
                    },
                    additionalProperties: false,
                },
            },
        }),
        additionalProperties: false,
    };
}

/**
 * The name of this rule.
 */
const name$j = "functional-parameters";
/**
 * The full name of this rule.
 */
const fullName$a = `${ruleNameScope}/${name$j}`;
const coreOptionsPropertiesSchema$2 = deepmerge(ignoreIdentifierPatternOptionSchema, ignorePrefixSelectorOptionSchema, {
    allowRestParameter: {
        type: "boolean",
    },
    allowArgumentsKeyword: {
        type: "boolean",
    },
    enforceParameterCount: {
        oneOf: [
            {
                type: "boolean",
                enum: [false],
            },
            {
                type: "string",
                enum: ["atLeastOne", "exactlyOne"],
            },
            {
                type: "object",
                properties: {
                    count: {
                        type: "string",
                        enum: ["atLeastOne", "exactlyOne"],
                    },
                    ignoreGettersAndSetters: {
                        type: "boolean",
                    },
                    ignoreLambdaExpression: {
                        type: "boolean",
                    },
                    ignoreIIFE: {
                        type: "boolean",
                    },
                },
                additionalProperties: false,
            },
        ],
    },
});
/**
 * The schema for the rule options.
 */
const schema$j = [overridableOptionsSchema(coreOptionsPropertiesSchema$2)];
/**
 * The default options for the rule.
 */
const defaultOptions$j = [
    {
        allowRestParameter: false,
        allowArgumentsKeyword: false,
        enforceParameterCount: {
            count: "atLeastOne",
            ignoreLambdaExpression: false,
            ignoreIIFE: true,
            ignoreGettersAndSetters: true,
        },
    },
];
/**
 * The possible error messages.
 */
const errorMessages$j = {
    restParam: "Unexpected rest parameter. Use a regular parameter of type array instead.",
    arguments: "Unexpected use of `arguments`. Use regular function arguments instead.",
    paramCountAtLeastOne: "Functions must have at least one parameter.",
    paramCountExactlyOne: "Functions must have exactly one parameter.",
};
/**
 * The meta data for this rule.
 */
const meta$k = {
    type: "suggestion",
    docs: {
        category: "Currying",
        description: "Enforce functional parameters.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: true,
    },
    messages: errorMessages$j,
    schema: schema$j,
};
/**
 * Get the rest parameter violations.
 */
function getRestParamViolations({ allowRestParameter }, node) {
    return !allowRestParameter && node.params.length > 0 && isRestElement(node.params.at(-1))
        ? [
            {
                node: node.params.at(-1),
                messageId: "restParam",
            },
        ]
        : [];
}
/**
 * Get the parameter count violations.
 */
function getParamCountViolations({ enforceParameterCount }, node) {
    if (enforceParameterCount === false ||
        (node.params.length === 0 &&
            typeof enforceParameterCount === "object" &&
            ((enforceParameterCount.ignoreIIFE && isIIFE(node)) ||
                (enforceParameterCount.ignoreLambdaExpression && isArgument(node)) ||
                (enforceParameterCount.ignoreGettersAndSetters && (isGetter(node) || isSetter(node)))))) {
        return [];
    }
    if (node.params.length === 0 &&
        (enforceParameterCount === "atLeastOne" ||
            (typeof enforceParameterCount === "object" && enforceParameterCount.count === "atLeastOne"))) {
        return [
            {
                node,
                messageId: "paramCountAtLeastOne",
            },
        ];
    }
    if (node.params.length !== 1 &&
        (enforceParameterCount === "exactlyOne" ||
            (typeof enforceParameterCount === "object" && enforceParameterCount.count === "exactlyOne"))) {
        return [
            {
                node,
                messageId: "paramCountExactlyOne",
            },
        ];
    }
    return [];
}
/**
 * Add the default options to the given options.
 */
function getOptionsWithDefaults$2(options) {
    if (options === null) {
        return null;
    }
    const topLevel = {
        ...defaultOptions$j[0],
        ...options,
    };
    return typeof topLevel.enforceParameterCount === "object"
        ? {
            ...topLevel,
            enforceParameterCount: {
                ...defaultOptions$j[0].enforceParameterCount,
                ...topLevel.enforceParameterCount,
            },
        }
        : topLevel;
}
/**
 * Check if the given function node has a reset parameter this rule.
 */
function checkFunction$3(node, context, rawOptions) {
    const options = upgradeRawOverridableOptions(rawOptions[0]);
    const optionsToUse = getOptionsWithDefaults$2(getCoreOptions(node, context, options));
    if (optionsToUse === null) {
        return {
            context,
            descriptors: [],
        };
    }
    const { ignoreIdentifierPattern } = optionsToUse;
    if (shouldIgnorePattern(node, context, ignoreIdentifierPattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    return {
        context,
        descriptors: [...getRestParamViolations(optionsToUse, node), ...getParamCountViolations(optionsToUse, node)],
    };
}
/**
 * Check if the given identifier is for the "arguments" keyword.
 */
function checkIdentifier(node, context, rawOptions) {
    if (node.name !== "arguments") {
        return {
            context,
            descriptors: [],
        };
    }
    const functionNode = getEnclosingFunction(node);
    const options = upgradeRawOverridableOptions(rawOptions[0]);
    const optionsToUse = getOptionsWithDefaults$2(functionNode === null ? options : getCoreOptions(functionNode, context, options));
    if (optionsToUse === null) {
        return {
            context,
            descriptors: [],
        };
    }
    const { ignoreIdentifierPattern } = optionsToUse;
    if (shouldIgnorePattern(node, context, ignoreIdentifierPattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    const { allowArgumentsKeyword } = optionsToUse;
    return {
        context,
        descriptors: !allowArgumentsKeyword && !isPropertyName(node) && !isPropertyAccess(node)
            ? [
                {
                    node,
                    messageId: "arguments",
                },
            ]
            : [],
    };
}
// Create the rule.
const rule$j = createRuleUsingFunction(name$j, meta$k, defaultOptions$j, (context, options) => {
    const [optionsObject] = options;
    const { ignorePrefixSelector } = optionsObject;
    const baseFunctionSelectors = ["ArrowFunctionExpression", "FunctionDeclaration", "FunctionExpression"];
    const ignoreSelectors = ignorePrefixSelector === undefined
        ? undefined
        : Array.isArray(ignorePrefixSelector)
            ? ignorePrefixSelector
            : [ignorePrefixSelector];
    const fullFunctionSelectors = baseFunctionSelectors.flatMap((baseSelector) => ignoreSelectors === undefined ? [baseSelector] : `:not(:matches(${ignoreSelectors.join(",")})) > ${baseSelector}`);
    return {
        ...Object.fromEntries(fullFunctionSelectors.map((selector) => [selector, checkFunction$3])),
        Identifier: checkIdentifier,
    };
});

/**
 * The name of this rule.
 */
const name$i = "immutable-data";
/**
 * The full name of this rule.
 */
const fullName$9 = `${ruleNameScope}/${name$i}`;
const coreOptionsPropertiesSchema$1 = deepmerge(ignoreIdentifierPatternOptionSchema, ignoreAccessorPatternOptionSchema, ignoreClassesOptionSchema, ignoreMapsAndSetsOptionSchema, {
    ignoreImmediateMutation: {
        type: "boolean",
    },
    ignoreNonConstDeclarations: {
        oneOf: [
            {
                type: "boolean",
            },
            {
                type: "object",
                properties: {
                    treatParametersAsConst: {
                        type: "boolean",
                    },
                },
                additionalProperties: false,
            },
        ],
    },
});
/**
 * The schema for the rule options.
 */
const schema$i = [overridableOptionsSchema(coreOptionsPropertiesSchema$1)];
/**
 * The default options for the rule.
 */
const defaultOptions$i = [
    {
        ignoreClasses: false,
        ignoreMapsAndSets: false,
        ignoreImmediateMutation: true,
        ignoreNonConstDeclarations: false,
    },
];
/**
 * The possible error messages.
 */
const errorMessages$i = {
    generic: "Modifying an existing object/array is not allowed.",
    object: "Modifying properties of existing object not allowed.",
    array: "Modifying an array is not allowed.",
    map: "Modifying a map is not allowed.",
    set: "Modifying a set is not allowed.",
};
/**
 * The meta data for this rule.
 */
const meta$j = {
    type: "suggestion",
    docs: {
        category: "No Mutations",
        description: "Enforce treating data as immutable.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: true,
    },
    messages: errorMessages$i,
    schema: schema$i,
};
/**
 * Array methods that mutate an array.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype#Methods#Mutator_methods
 */
const arrayMutatorMethods = new Set([
    "copyWithin",
    "fill",
    "pop",
    "push",
    "reverse",
    "shift",
    "sort",
    "splice",
    "unshift",
]);
/**
 * Array methods that return a new object (or array) without mutating the original.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype#Methods#Accessor_methods
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype#Iteration_methods
 */
const arrayNewObjectReturningMethods = new Set(["concat", "slice", "filter", "map", "reduce", "reduceRight"]);
/**
 * Array constructor functions that create a new array.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Methods
 */
const arrayConstructorFunctions = new Set(["from", "of"]);
/**
 * Map methods that mutate an map.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
 */
const mapMutatorMethods = new Set(["clear", "delete", "set"]);
/**
 * Map methods that return a new object without mutating the original.
 */
const mapNewObjectReturningMethods = new Set([]);
/**
 * Set methods that mutate an set.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
 */
const setMutatorMethods = new Set(["add", "clear", "delete"]);
/**
 * Set methods that return a new object without mutating the original.
 */
const setNewObjectReturningMethods = new Set(["difference", "intersection", "symmetricDifference", "union"]);
/**
 * Object constructor functions that mutate an object.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#Methods_of_the_Object_constructor
 */
const objectConstructorMutatorFunctions = new Set(["assign", "defineProperties", "defineProperty", "setPrototypeOf"]);
/**
 * Object constructor functions that return new objects.
 */
const objectConstructorNewObjectReturningMethods = new Set([
    "create",
    "entries",
    "fromEntries",
    "getOwnPropertyDescriptor",
    "getOwnPropertyDescriptors",
    "getOwnPropertyNames",
    "getOwnPropertySymbols",
    "groupBy",
    "keys",
    "values",
]);
/**
 * String constructor functions that return new objects.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Methods
 */
const stringConstructorNewObjectReturningMethods = new Set(["split"]);
/**
 * Check if the given assignment expression violates this rule.
 */
function checkAssignmentExpression(node, context, rawOptions) {
    const options = upgradeRawOverridableOptions(rawOptions[0]);
    const rootNode = findRootIdentifier(node.left) ?? node.left;
    const optionsToUse = getOptionsWithDefaults$1(getCoreOptions(rootNode, context, options));
    if (optionsToUse === null) {
        return {
            context,
            descriptors: [],
        };
    }
    const { ignoreIdentifierPattern, ignoreAccessorPattern, ignoreNonConstDeclarations, ignoreClasses } = optionsToUse;
    if (!isMemberExpression(node.left) ||
        shouldIgnoreClasses(node, context, ignoreClasses) ||
        shouldIgnorePattern(node, context, ignoreIdentifierPattern, ignoreAccessorPattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    if (ignoreNonConstDeclarations !== false) {
        const rootIdentifier = findRootIdentifier(node.left.object);
        if (rootIdentifier !== undefined &&
            isDefinedByMutableVariable(rootIdentifier, context, (variableNode) => ignoreNonConstDeclarations === true ||
                !ignoreNonConstDeclarations.treatParametersAsConst ||
                shouldIgnorePattern(variableNode, context, ignoreIdentifierPattern, ignoreAccessorPattern))) {
            return {
                context,
                descriptors: [],
            };
        }
    }
    return {
        context,
        descriptors: 
        // Allow if in a constructor - allow for field initialization.
        isInConstructor(node) ? [] : [{ node, messageId: "generic" }],
    };
}
/**
 * Check if the given node violates this rule.
 */
function checkUnaryExpression(node, context, rawOptions) {
    const options = upgradeRawOverridableOptions(rawOptions[0]);
    const rootNode = findRootIdentifier(node.argument) ?? node.argument;
    const optionsToUse = getOptionsWithDefaults$1(getCoreOptions(rootNode, context, options));
    if (optionsToUse === null) {
        return {
            context,
            descriptors: [],
        };
    }
    const { ignoreIdentifierPattern, ignoreAccessorPattern, ignoreNonConstDeclarations, ignoreClasses } = optionsToUse;
    if (!isMemberExpression(node.argument) ||
        shouldIgnoreClasses(node, context, ignoreClasses) ||
        shouldIgnorePattern(node, context, ignoreIdentifierPattern, ignoreAccessorPattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    if (ignoreNonConstDeclarations !== false) {
        const rootIdentifier = findRootIdentifier(node.argument.object);
        if (rootIdentifier !== undefined &&
            isDefinedByMutableVariable(rootIdentifier, context, (variableNode) => ignoreNonConstDeclarations === true ||
                !ignoreNonConstDeclarations.treatParametersAsConst ||
                shouldIgnorePattern(variableNode, context, ignoreIdentifierPattern, ignoreAccessorPattern))) {
            return {
                context,
                descriptors: [],
            };
        }
    }
    return {
        context,
        descriptors: node.operator === "delete" ? [{ node, messageId: "generic" }] : [],
    };
}
/**
 * Check if the given node violates this rule.
 */
function checkUpdateExpression(node, context, rawOptions) {
    const options = upgradeRawOverridableOptions(rawOptions[0]);
    const rootNode = findRootIdentifier(node.argument) ?? node.argument;
    const optionsToUse = getOptionsWithDefaults$1(getCoreOptions(rootNode, context, options));
    if (optionsToUse === null) {
        return {
            context,
            descriptors: [],
        };
    }
    const { ignoreIdentifierPattern, ignoreAccessorPattern, ignoreNonConstDeclarations, ignoreClasses } = optionsToUse;
    if (!isMemberExpression(node.argument) ||
        shouldIgnoreClasses(node.argument, context, ignoreClasses) ||
        shouldIgnorePattern(node.argument, context, ignoreIdentifierPattern, ignoreAccessorPattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    if (ignoreNonConstDeclarations !== false) {
        const rootIdentifier = findRootIdentifier(node.argument.object);
        if (rootIdentifier !== undefined &&
            isDefinedByMutableVariable(rootIdentifier, context, (variableNode) => ignoreNonConstDeclarations === true ||
                !ignoreNonConstDeclarations.treatParametersAsConst ||
                shouldIgnorePattern(variableNode, context, ignoreIdentifierPattern, ignoreAccessorPattern))) {
            return {
                context,
                descriptors: [],
            };
        }
    }
    return {
        context,
        descriptors: [{ node, messageId: "generic" }],
    };
}
/**
 * Check if the given the given MemberExpression is part of a chain and
 * immediately follows a method/function call that returns a new array.
 *
 * If this is the case, then the given MemberExpression is allowed to be
 * a mutator method call.
 */
function isInChainCallAndFollowsNew(node, context) {
    if (isMemberExpression(node)) {
        return isInChainCallAndFollowsNew(node.object, context);
    }
    if (isTSAsExpression(node)) {
        return isInChainCallAndFollowsNew(node.expression, context);
    }
    // Check for: [0, 1, 2]
    if (isArrayExpression(node)) {
        return true;
    }
    // Check for: new Array()
    if (isNewExpression(node)) {
        const type = getTypeOfNode(node.callee, context);
        return (isArrayConstructorType(context, type) ||
            isMapConstructorType(context, type) ||
            isSetConstructorType(context, type));
    }
    if (isCallExpression(node) && isMemberExpression(node.callee) && isIdentifier(node.callee.property)) {
        // Check for: Array.from(iterable)
        if (arrayConstructorFunctions.has(node.callee.property.name) &&
            isArrayConstructorType(context, getTypeOfNode(node.callee.object, context))) {
            return true;
        }
        // Check for: array.slice(0)
        if (arrayNewObjectReturningMethods.has(node.callee.property.name)) {
            return true;
        }
        if (mapNewObjectReturningMethods.has(node.callee.property.name)) {
            return true;
        }
        // Check for: set.difference(otherSet)
        if (setNewObjectReturningMethods.has(node.callee.property.name)) {
            return true;
        }
        // Check for: Object.entries(object)
        if (objectConstructorNewObjectReturningMethods.has(node.callee.property.name) &&
            isObjectConstructorType(context, getTypeOfNode(node.callee.object, context))) {
            return true;
        }
        // Check for: "".split("")
        if (stringConstructorNewObjectReturningMethods.has(node.callee.property.name) &&
            getTypeOfNode(node.callee.object, context).isStringLiteral()) {
            return true;
        }
    }
    return false;
}
/**
 * Add the default options to the given options.
 */
function getOptionsWithDefaults$1(options) {
    if (options === null) {
        return null;
    }
    return {
        ...defaultOptions$i[0],
        ...options,
    };
}
/**
 * Check if the given node violates this rule.
 */
function checkCallExpression$1(node, context, rawOptions) {
    const options = upgradeRawOverridableOptions(rawOptions[0]);
    const rootNode = findRootIdentifier(node.callee) ?? node.callee;
    const optionsToUse = getOptionsWithDefaults$1(getCoreOptions(rootNode, context, options));
    if (optionsToUse === null) {
        return {
            context,
            descriptors: [],
        };
    }
    const { ignoreIdentifierPattern, ignoreAccessorPattern, ignoreNonConstDeclarations, ignoreClasses } = optionsToUse;
    // Not potential object mutation?
    if (!isMemberExpression(node.callee) ||
        !isIdentifier(node.callee.property) ||
        shouldIgnoreClasses(node.callee.object, context, ignoreClasses) ||
        shouldIgnorePattern(node.callee.object, context, ignoreIdentifierPattern, ignoreAccessorPattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    const { ignoreImmediateMutation, ignoreMapsAndSets } = optionsToUse;
    // Array mutation?
    if (arrayMutatorMethods.has(node.callee.property.name) &&
        (!ignoreImmediateMutation || !isInChainCallAndFollowsNew(node.callee, context)) &&
        isArrayType(context, getTypeOfNode(node.callee.object, context))) {
        if (ignoreNonConstDeclarations === false) {
            return {
                context,
                descriptors: [{ node, messageId: "array" }],
            };
        }
        const rootIdentifier = findRootIdentifier(node.callee.object);
        if (rootIdentifier === undefined ||
            !isDefinedByMutableVariable(rootIdentifier, context, (variableNode) => ignoreNonConstDeclarations === true ||
                !ignoreNonConstDeclarations.treatParametersAsConst ||
                shouldIgnorePattern(variableNode, context, ignoreIdentifierPattern, ignoreAccessorPattern))) {
            return {
                context,
                descriptors: [{ node, messageId: "array" }],
            };
        }
    }
    if (!ignoreMapsAndSets) {
        // Set mutation?
        if (setMutatorMethods.has(node.callee.property.name) &&
            (!ignoreImmediateMutation || !isInChainCallAndFollowsNew(node.callee, context)) &&
            isSetType(context, getTypeOfNode(node.callee.object, context))) {
            if (ignoreNonConstDeclarations === false) {
                return {
                    context,
                    descriptors: [{ node, messageId: "set" }],
                };
            }
            const rootIdentifier = findRootIdentifier(node.callee.object);
            if (rootIdentifier === undefined ||
                !isDefinedByMutableVariable(rootIdentifier, context, (variableNode) => ignoreNonConstDeclarations === true ||
                    !ignoreNonConstDeclarations.treatParametersAsConst ||
                    shouldIgnorePattern(variableNode, context, ignoreIdentifierPattern, ignoreAccessorPattern))) {
                return {
                    context,
                    descriptors: [{ node, messageId: "set" }],
                };
            }
        }
        // Map mutation?
        if (mapMutatorMethods.has(node.callee.property.name) &&
            (!ignoreImmediateMutation || !isInChainCallAndFollowsNew(node.callee, context)) &&
            isMapType(context, getTypeOfNode(node.callee.object, context))) {
            if (ignoreNonConstDeclarations === false) {
                return {
                    context,
                    descriptors: [{ node, messageId: "map" }],
                };
            }
            const rootIdentifier = findRootIdentifier(node.callee.object);
            if (rootIdentifier === undefined ||
                !isDefinedByMutableVariable(rootIdentifier, context, (variableNode) => ignoreNonConstDeclarations === true ||
                    !ignoreNonConstDeclarations.treatParametersAsConst ||
                    shouldIgnorePattern(variableNode, context, ignoreIdentifierPattern, ignoreAccessorPattern))) {
                return {
                    context,
                    descriptors: [{ node, messageId: "map" }],
                };
            }
        }
    }
    // Non-array object mutation (ex. Object.assign on identifier)?
    if (objectConstructorMutatorFunctions.has(node.callee.property.name) &&
        node.arguments.length >= 2 &&
        (isIdentifier(node.arguments[0]) || isMemberExpression(node.arguments[0])) &&
        !shouldIgnoreClasses(node.arguments[0], context, ignoreClasses) &&
        !shouldIgnorePattern(node.arguments[0], context, ignoreIdentifierPattern, ignoreAccessorPattern) &&
        isObjectConstructorType(context, getTypeOfNode(node.callee.object, context))) {
        if (ignoreNonConstDeclarations === false) {
            return {
                context,
                descriptors: [{ node, messageId: "object" }],
            };
        }
        const rootIdentifier = findRootIdentifier(node.callee.object);
        if (rootIdentifier === undefined ||
            !isDefinedByMutableVariable(rootIdentifier, context, (variableNode) => ignoreNonConstDeclarations === true ||
                !ignoreNonConstDeclarations.treatParametersAsConst ||
                shouldIgnorePattern(variableNode, context, ignoreIdentifierPattern, ignoreAccessorPattern))) {
            return {
                context,
                descriptors: [{ node, messageId: "object" }],
            };
        }
    }
    return {
        context,
        descriptors: [],
    };
}
// Create the rule.
const rule$i = createRule(name$i, meta$j, defaultOptions$i, {
    AssignmentExpression: checkAssignmentExpression,
    UnaryExpression: checkUnaryExpression,
    UpdateExpression: checkUpdateExpression,
    CallExpression: checkCallExpression$1,
});

/**
 * The name of this rule.
 */
const name$h = "no-class-inheritance";
/**
 * The schema for the rule options.
 */
const schema$h = [
    {
        type: "object",
        properties: deepmerge(ignoreIdentifierPatternOptionSchema, ignoreCodePatternOptionSchema),
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$h = [{}];
/**
 * The possible error messages.
 */
const errorMessages$h = {
    abstract: "Unexpected abstract class.",
    extends: "Unexpected inheritance, use composition instead.",
};
/**
 * The meta data for this rule.
 */
const meta$i = {
    type: "suggestion",
    docs: {
        category: "No Other Paradigms",
        description: "Disallow inheritance in classes.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: false,
    },
    messages: errorMessages$h,
    schema: schema$h,
};
/**
 * Check if the given class node violates this rule.
 */
function checkClass$1(node, context, options) {
    const [optionsObject] = options;
    const { ignoreIdentifierPattern, ignoreCodePattern } = optionsObject;
    const mut_descriptors = [];
    if (!shouldIgnorePattern(node, context, ignoreIdentifierPattern, undefined, ignoreCodePattern)) {
        if (node.abstract) {
            const nodeText = context.sourceCode.getText(node);
            const abstractRelativeIndex = nodeText.indexOf("abstract");
            const abstractIndex = context.sourceCode.getIndexFromLoc(node.loc.start) + abstractRelativeIndex;
            const start = context.sourceCode.getLocFromIndex(abstractIndex);
            const end = context.sourceCode.getLocFromIndex(abstractIndex + "abstract".length);
            mut_descriptors.push({
                node,
                loc: {
                    start,
                    end,
                },
                messageId: "abstract",
            });
        }
        if (node.superClass !== null) {
            const nodeText = context.sourceCode.getText(node);
            const extendsRelativeIndex = nodeText.indexOf("extends");
            const extendsIndex = context.sourceCode.getIndexFromLoc(node.loc.start) + extendsRelativeIndex;
            const start = context.sourceCode.getLocFromIndex(extendsIndex);
            const { end } = node.superClass.loc;
            mut_descriptors.push({
                node,
                loc: {
                    start,
                    end,
                },
                messageId: "extends",
            });
        }
    }
    return {
        context,
        descriptors: mut_descriptors,
    };
}
// Create the rule.
const rule$h = createRule(name$h, meta$i, defaultOptions$h, {
    ClassDeclaration: checkClass$1,
    ClassExpression: checkClass$1,
});

/**
 * The name of this rule.
 */
const name$g = "no-classes";
/**
 * The full name of this rule.
 */
const fullName$8 = `${ruleNameScope}/${name$g}`;
/**
 * The schema for the rule options.
 */
const schema$g = [
    {
        type: "object",
        properties: deepmerge(ignoreIdentifierPatternOptionSchema, ignoreCodePatternOptionSchema),
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$g = [{}];
/**
 * The possible error messages.
 */
const errorMessages$g = {
    generic: "Unexpected class, use functions not classes.",
};
/**
 * The meta data for this rule.
 */
const meta$h = {
    type: "suggestion",
    docs: {
        category: "No Other Paradigms",
        description: "Disallow classes.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: false,
    },
    messages: errorMessages$g,
    schema: schema$g,
};
/**
 * Check if the given class node violates this rule.
 */
function checkClass(node, context, options) {
    const [optionsObject] = options;
    const { ignoreIdentifierPattern, ignoreCodePattern } = optionsObject;
    if (shouldIgnorePattern(node, context, ignoreIdentifierPattern, undefined, ignoreCodePattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    return { context, descriptors: [{ node, messageId: "generic" }] };
}
// Create the rule.
const rule$g = createRule(name$g, meta$h, defaultOptions$g, {
    ClassDeclaration: checkClass,
    ClassExpression: checkClass,
});

const require = createRequire(import.meta.url);
const tsApiUtils = (typescript === undefined
    ? undefined
    : (() => {
        try {
            return require("ts-api-utils");
        }
        catch {
            return undefined;
        }
    })());
// export default (await (() => {
//   if (ts !== undefined) {
//     return import("ts-api-utils").catch(() => undefined);
//   }
//   return Promise.resolve(undefined);
// })()) as typeof tsApiUtils | undefined;

/**
 * The name of this .
 */
const name$f = "no-conditional-statements";
/**
 * The full name of this rule.
 */
const fullName$7 = `${ruleNameScope}/${name$f}`;
/**
 * The schema for the rule options.
 */
const schema$f = [
    {
        type: "object",
        properties: deepmerge(ignoreCodePatternOptionSchema, {
            allowReturningBranches: {
                oneOf: [
                    {
                        type: "boolean",
                    },
                    {
                        type: "string",
                        enum: ["ifExhaustive"],
                    },
                ],
            },
        }),
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$f = [{ allowReturningBranches: false }];
/**
 * The possible error messages.
 */
const errorMessages$f = {
    incompleteBranch: "Incomplete branch, every branch in a conditional statement must contain a return statement.",
    incompleteIf: "Incomplete if, it must have an else statement and every branch must contain a return statement.",
    incompleteSwitch: "Incomplete switch, it must be exhaustive or have an default case and every case must contain a return statement.",
    unexpectedIf: "Unexpected if, use a conditional expression (ternary operator) instead.",
    unexpectedSwitch: "Unexpected switch, use a conditional expression (ternary operator) instead.",
};
/**
 * The meta data for this rule.
 */
const meta$g = {
    type: "suggestion",
    docs: {
        category: "No Statements",
        description: "Disallow conditional statements.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: true,
    },
    messages: errorMessages$f,
    schema: schema$f,
};
/**
 * Report the given node as an incomplete branch violation.
 *
 * @param node - The node to report.
 * @returns A violation rule result.
 */
function incompleteBranchViolation(node) {
    return [{ node, messageId: "incompleteBranch" }];
}
/**
 * Get a function that tests if the given statement is never returning.
 */
function getIsNeverExpressions(context) {
    return (statement) => {
        if (isExpressionStatement(statement)) {
            const expressionStatementType = getTypeOfNode(statement.expression, context);
            return expressionStatementType !== null && tsApiUtils?.isIntrinsicNeverType(expressionStatementType) === true;
        }
        return false;
    };
}
/**
 * Is the given statement, when inside an if statement, a returning branch?
 */
function isIfReturningBranch(statement) {
    return (
    // Another instance of this rule will check nested if statements.
    isIfStatement(statement) ||
        isReturnStatement(statement) ||
        isThrowStatement(statement) ||
        isBreakStatement(statement) ||
        isContinueStatement(statement));
}
/**
 * Get all of the violations in the given if statement assuming if statements
 * are allowed.
 */
function getIfBranchViolations(node, context) {
    const branches = [node.consequent, node.alternate];
    const violations = branches.filter((branch) => {
        if (branch === null || isIfReturningBranch(branch)) {
            return false;
        }
        if (isExpressionStatement(branch)) {
            const expressionStatementType = getTypeOfNode(branch.expression, context);
            if (expressionStatementType !== null && tsApiUtils?.isIntrinsicNeverType(expressionStatementType) === true) {
                return false;
            }
        }
        if (isBlockStatement(branch)) {
            if (branch.body.some(isIfReturningBranch)) {
                return false;
            }
            const isNeverExpressions = getIsNeverExpressions(context);
            if (branch.body.some(isNeverExpressions)) {
                return false;
            }
        }
        return true;
    });
    return violations.flatMap(incompleteBranchViolation);
}
/**
 * Get all of the violations in the given switch statement assuming switch
 * statements are allowed.
 */
function getSwitchViolations(node, context) {
    const isNeverExpressions = getIsNeverExpressions(context);
    const label = isLabeledStatement(node.parent) ? node.parent.label.name : null;
    const violations = node.cases.filter((branch) => {
        if (branch.consequent.length === 0) {
            return false;
        }
        if (branch.consequent.some(isSwitchReturningBranch)) {
            return false;
        }
        if (branch.consequent.every(isBlockStatement)) {
            const lastBlock = branch.consequent.at(-1);
            if (lastBlock.body.some(isSwitchReturningBranch)) {
                return false;
            }
            if (lastBlock.body.some(isNeverExpressions)) {
                return false;
            }
        }
        return !branch.consequent.some(isNeverExpressions);
    });
    return violations.flatMap(incompleteBranchViolation);
    /**
     * Is the given statement, when inside a switch statement, a returning branch?
     */
    function isSwitchReturningBranch(statement) {
        return (
        // Another instance of this rule will check nested switch statements.
        isSwitchStatement(statement) ||
            isReturnStatement(statement) ||
            isThrowStatement(statement) ||
            (isBreakStatement(statement) && statement.label !== null && statement.label.name !== label) ||
            isContinueStatement(statement));
    }
}
/**
 * Does the given if statement violate this rule if it must be exhaustive.
 */
function isExhaustiveIfViolation(node) {
    return node.alternate === null;
}
/**
 * Does the given typed switch statement violate this rule if it must be exhaustive.
 */
function isExhaustiveTypeSwitchViolation(node, context) {
    const discriminantType = getTypeOfNode(node.discriminant, context);
    if (!discriminantType?.isUnion()) {
        return true;
    }
    const caseTypes = node.cases.reduce((types, c) => new Set([...types, getTypeOfNode(c.test, context)]), new Set());
    return discriminantType.types.some((unionType) => !caseTypes.has(unionType));
}
/**
 * Does the given switch statement violate this rule if it must be exhaustive.
 */
function isExhaustiveSwitchViolation(node, context) {
    return (
    // No cases defined.
    node.cases.every((c) => c.test !== null) ? isExhaustiveTypeSwitchViolation(node, context) : false);
}
/**
 * Check if the given IfStatement violates this rule.
 */
function checkIfStatement(node, context, options) {
    const [{ allowReturningBranches, ignoreCodePattern }] = options;
    if (shouldIgnorePattern(node.test, context, undefined, undefined, ignoreCodePattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    return {
        context,
        descriptors: allowReturningBranches === false
            ? [{ node, messageId: "unexpectedIf" }]
            : allowReturningBranches === "ifExhaustive"
                ? isExhaustiveIfViolation(node)
                    ? [{ node, messageId: "incompleteIf" }]
                    : getIfBranchViolations(node, context)
                : getIfBranchViolations(node, context),
    };
}
/**
 * Check if the given SwitchStatement violates this rule.
 */
function checkSwitchStatement(node, context, options) {
    const [{ allowReturningBranches }] = options;
    return {
        context,
        descriptors: allowReturningBranches === false
            ? [{ node, messageId: "unexpectedSwitch" }]
            : allowReturningBranches === "ifExhaustive"
                ? isExhaustiveSwitchViolation(node, context)
                    ? [{ node, messageId: "incompleteSwitch" }]
                    : getSwitchViolations(node, context)
                : getSwitchViolations(node, context),
    };
}
// Create the rule.
const rule$f = createRule(name$f, meta$g, defaultOptions$f, {
    IfStatement: checkIfStatement,
    SwitchStatement: checkSwitchStatement,
});

/**
 * The name of this rule.
 */
const name$e = "no-expression-statements";
/**
 * The full name of this rule.
 */
const fullName$6 = `${ruleNameScope}/${name$e}`;
/**
 * The schema for the rule options.
 */
const schema$e = [
    {
        type: "object",
        properties: deepmerge(ignoreCodePatternOptionSchema, {
            ignoreVoid: {
                type: "boolean",
            },
            ignoreSelfReturning: {
                type: "boolean",
            },
        }),
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$e = [
    {
        ignoreVoid: false,
        ignoreSelfReturning: false,
    },
];
/**
 * The possible error messages.
 */
const errorMessages$e = {
    generic: "Using expressions to cause side-effects not allowed.",
};
/**
 * The meta data for this rule.
 */
const meta$f = {
    type: "suggestion",
    docs: {
        category: "No Statements",
        description: "Disallow expression statements.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: true,
    },
    messages: errorMessages$e,
    schema: schema$e,
};
/**
 * Check if the given ExpressionStatement violates this rule.
 */
function checkExpressionStatement(node, context, options) {
    const [optionsObject] = options;
    const { ignoreCodePattern } = optionsObject;
    if (shouldIgnorePattern(node, context, undefined, undefined, ignoreCodePattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    // Allow specifying directive prologues and using yield expressions.
    if (isDirectivePrologue(node) || isYieldExpression(node.expression)) {
        return {
            context,
            descriptors: [],
        };
    }
    const { ignoreVoid, ignoreSelfReturning } = optionsObject;
    if ((ignoreVoid || ignoreSelfReturning) && isCallExpression(node.expression)) {
        const returnType = getTypeOfNode(node.expression, context);
        if (returnType === null) {
            return {
                context,
                descriptors: [{ node, messageId: "generic" }],
            };
        }
        if (ignoreVoid &&
            (tsApiUtils?.isIntrinsicVoidType(returnType) === true ||
                ("typeArguments" in returnType &&
                    isPromiseType(context, returnType) &&
                    returnType.typeArguments.length > 0 &&
                    tsApiUtils?.isIntrinsicVoidType(returnType.typeArguments[0]) === true))) {
            return {
                context,
                descriptors: [],
            };
        }
        if (ignoreSelfReturning) {
            const type = getTypeOfNode(node.expression.callee, context);
            if (type !== null) {
                const declaration = type.getSymbol()?.valueDeclaration;
                if (typescript !== undefined &&
                    declaration !== undefined &&
                    typescript.isFunctionLike(declaration) &&
                    !typescript.isArrowFunction(declaration) &&
                    "body" in declaration &&
                    declaration.body !== undefined &&
                    typescript.isBlock(declaration.body)) {
                    const returnStatements = declaration.body.statements.filter(typescript.isReturnStatement);
                    if (returnStatements.every((statement) => statement.expression !== undefined && tsApiUtils?.isThisKeyword(statement.expression) === true)) {
                        return {
                            context,
                            descriptors: [],
                        };
                    }
                }
            }
        }
    }
    return {
        context,
        descriptors: [{ node, messageId: "generic" }],
    };
}
// Create the rule.
const rule$e = createRule(name$e, meta$f, defaultOptions$e, {
    ExpressionStatement: checkExpressionStatement,
});

/**
 * The name of this rule.
 */
const name$d = "no-let";
/**
 * The full name of this rule.
 */
const fullName$5 = `${ruleNameScope}/${name$d}`;
/**
 * The schema for the rule options.
 */
const schema$d = [
    {
        type: "object",
        properties: deepmerge(ignoreIdentifierPatternOptionSchema, {
            allowInForLoopInit: {
                type: "boolean",
            },
            allowInFunctions: {
                type: "boolean",
            },
        }),
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$d = [
    {
        allowInForLoopInit: false,
        allowInFunctions: false,
    },
];
/**
 * The possible error messages.
 */
const errorMessages$d = {
    generic: "Unexpected let, use const instead.",
};
/**
 * The meta data for this rule.
 */
const meta$e = {
    type: "suggestion",
    docs: {
        category: "No Mutations",
        description: "Disallow mutable variables.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: false,
    },
    messages: errorMessages$d,
    schema: schema$d,
};
/**
 * Check if the given VariableDeclaration violates this rule.
 */
function checkVariableDeclaration(node, context, options) {
    const [optionsObject] = options;
    const { allowInForLoopInit, ignoreIdentifierPattern, allowInFunctions } = optionsObject;
    if (node.kind !== "let" ||
        shouldIgnoreInFunction(node, context, allowInFunctions) ||
        shouldIgnorePattern(node, context, ignoreIdentifierPattern) ||
        (allowInForLoopInit && isInForLoopInitializer(node))) {
        return {
            context,
            descriptors: [],
        };
    }
    return {
        context,
        descriptors: [{ node, messageId: "generic" }],
    };
}
// Create the rule.
const rule$d = createRule(name$d, meta$e, defaultOptions$d, {
    VariableDeclaration: checkVariableDeclaration,
});

/**
 * The name of this rule.
 */
const name$c = "no-loop-statements";
/**
 * The schema for the rule options.
 */
const schema$c = [];
/**
 * The default options for the rule.
 */
const defaultOptions$c = [{}];
/**
 * The possible error messages.
 */
const errorMessages$c = {
    generic: "Unexpected loop, use map or reduce instead.",
};
/**
 * The meta data for this rule.
 */
const meta$d = {
    type: "suggestion",
    docs: {
        category: "No Statements",
        description: "Disallow imperative loops.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: false,
    },
    messages: errorMessages$c,
    schema: schema$c,
};
/**
 * Check if the given loop violates this rule.
 */
function checkLoop(node, context) {
    // All loops violate this rule.
    return { context, descriptors: [{ node, messageId: "generic" }] };
}
// Create the rule.
const rule$c = createRule(name$c, meta$d, defaultOptions$c, {
    ForStatement: checkLoop,
    ForInStatement: checkLoop,
    ForOfStatement: checkLoop,
    WhileStatement: checkLoop,
    DoWhileStatement: checkLoop,
});

/**
 * The name of this rule.
 */
const name$b = "no-mixed-types";
/**
 * The schema for the rule options.
 */
const schema$b = [
    {
        type: "object",
        properties: {
            checkInterfaces: {
                type: "boolean",
            },
            checkTypeLiterals: {
                type: "boolean",
            },
        },
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$b = [
    {
        checkInterfaces: true,
        checkTypeLiterals: true,
    },
];
/**
 * The possible error messages.
 */
const errorMessages$b = {
    generic: "Only the same kind of members allowed in types.",
};
/**
 * The meta data for this rule.
 */
const meta$c = {
    type: "suggestion",
    docs: {
        category: "No Other Paradigms",
        description: "Restrict types so that only members of the same kind are allowed in them.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: true,
    },
    messages: errorMessages$b,
    schema: schema$b,
};
/**
 * Does the given type elements violate the rule.
 */
function hasTypeElementViolations(typeElements, context) {
    return !typeElements
        .map((member) => isTSMethodSignature(member) ||
        isTSCallSignatureDeclaration(member) ||
        isTSConstructSignatureDeclaration(member) ||
        ((isTSPropertySignature(member) || isTSIndexSignature(member)) &&
            member.typeAnnotation !== undefined &&
            (isTSFunctionType(member.typeAnnotation.typeAnnotation) ||
                isFunctionLikeType(getTypeOfNode(member, context)))))
        .every((isFunction, _, array) => array[0] === isFunction);
}
/**
 * Check if the given TSInterfaceDeclaration violates this rule.
 */
function checkTSInterfaceDeclaration(node, context, options) {
    return {
        context,
        descriptors: hasTypeElementViolations(node.body.body, context) ? [{ node, messageId: "generic" }] : [],
    };
}
/**
 * Check if the given TSTypeAliasDeclaration violates this rule.
 */
function checkTSTypeAliasDeclaration(node, context, options) {
    return {
        context,
        descriptors: 
        // TypeLiteral.
        (isTSTypeLiteral(node.typeAnnotation) && hasTypeElementViolations(node.typeAnnotation.members, context)) ||
            // TypeLiteral inside `Readonly<>`.
            (isTSTypeReference(node.typeAnnotation) &&
                isIdentifier(node.typeAnnotation.typeName) &&
                node.typeAnnotation.typeArguments !== undefined &&
                node.typeAnnotation.typeArguments.params.length === 1 &&
                isTSTypeLiteral(node.typeAnnotation.typeArguments.params[0]) &&
                hasTypeElementViolations(node.typeAnnotation.typeArguments.params[0].members, context))
            ? [{ node, messageId: "generic" }]
            : [],
    };
}
// Create the rule.
const rule$b = createRuleUsingFunction(name$b, meta$c, defaultOptions$b, (context, options) => {
    const [{ checkInterfaces, checkTypeLiterals }] = options;
    return Object.fromEntries([
        ["TSInterfaceDeclaration", checkInterfaces ? checkTSInterfaceDeclaration : undefined],
        ["TSTypeAliasDeclaration", checkTypeLiterals ? checkTSTypeAliasDeclaration : undefined],
    ].filter(([sel, fn]) => fn !== undefined));
});

/**
 * The name of this rule.
 */
const name$a = "no-promise-reject";
/**
 * The schema for the rule options.
 */
const schema$a = [];
/**
 * The default options for the rule.
 */
const defaultOptions$a = [{}];
/**
 * The possible error messages.
 */
const errorMessages$a = {
    generic: "Unexpected rejection, resolve an error instead.",
};
/**
 * The meta data for this rule.
 */
const meta$b = {
    type: "suggestion",
    docs: {
        category: "No Exceptions",
        description: "Disallow rejecting promises.",
        recommended: false,
        recommendedSeverity: "error",
        requiresTypeChecking: false,
    },
    messages: errorMessages$a,
    schema: schema$a,
};
/**
 * Check if the given CallExpression violates this rule.
 */
function checkCallExpression(node, context) {
    return {
        context,
        descriptors: 
        // TODO: Better Promise type detection.
        isMemberExpression(node.callee) &&
            isIdentifier(node.callee.object) &&
            isIdentifier(node.callee.property) &&
            node.callee.object.name === "Promise" &&
            node.callee.property.name === "reject"
            ? [{ node, messageId: "generic" }]
            : [],
    };
}
/**
 * Check if the given NewExpression is for a Promise and it has a callback that rejects.
 */
function checkNewExpression(node, context) {
    return {
        context,
        descriptors: 
        // TODO: Better Promise type detection.
        isIdentifier(node.callee) &&
            node.callee.name === "Promise" &&
            node.arguments[0] !== undefined &&
            isFunctionLike(node.arguments[0]) &&
            node.arguments[0].params.length === 2
            ? [{ node: node.arguments[0].params[1], messageId: "generic" }]
            : [],
    };
}
/**
 * Check if the given ThrowStatement violates this rule.
 */
function checkThrowStatement$1(node, context) {
    const enclosingFunction = getEnclosingFunction(node);
    if (enclosingFunction?.async !== true) {
        return { context, descriptors: [] };
    }
    const enclosingTryStatement = getEnclosingTryStatement(node);
    if (enclosingTryStatement === null ||
        getEnclosingFunction(enclosingTryStatement) !== enclosingFunction ||
        enclosingTryStatement.handler === null) {
        return {
            context,
            descriptors: [{ node, messageId: "generic" }],
        };
    }
    return {
        context,
        descriptors: [],
    };
}
// Create the rule.
const rule$a = createRule(name$a, meta$b, defaultOptions$a, {
    CallExpression: checkCallExpression,
    NewExpression: checkNewExpression,
    ThrowStatement: checkThrowStatement$1,
});

/**
 * The name of this rule.
 */
const name$9 = "no-return-void";
/**
 * The schema for the rule options.
 */
const schema$9 = [
    {
        type: "object",
        properties: {
            allowNull: {
                type: "boolean",
            },
            allowUndefined: {
                type: "boolean",
            },
            ignoreInferredTypes: {
                type: "boolean",
            },
        },
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$9 = [
    {
        allowNull: true,
        allowUndefined: true,
        ignoreInferredTypes: false,
    },
];
/**
 * The possible error messages.
 */
const errorMessages$9 = {
    generic: "Function must return a value.",
};
/**
 * The meta data for this rule.
 */
const meta$a = {
    type: "suggestion",
    docs: {
        category: "No Statements",
        description: "Disallow functions that don't return anything.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: true,
    },
    messages: errorMessages$9,
    schema: schema$9,
};
/**
 * Check if the given function node violates this rule.
 */
function checkFunction$2(node, context, options) {
    const [{ ignoreInferredTypes, allowNull, allowUndefined }] = options;
    if (node.returnType === undefined) {
        if (!ignoreInferredTypes && isFunctionLike(node)) {
            const functionType = getTypeOfNode(node, context);
            const returnType = functionType?.getCallSignatures()?.[0]?.getReturnType();
            if (returnType !== undefined &&
                tsApiUtils !== undefined &&
                (tsApiUtils.isIntrinsicVoidType(returnType) ||
                    (!allowNull && tsApiUtils.isIntrinsicNullType(returnType)) ||
                    (!allowUndefined && tsApiUtils.isIntrinsicUndefinedType(returnType)))) {
                return {
                    context,
                    descriptors: [{ node, messageId: "generic" }],
                };
            }
        }
    }
    else if (isTSVoidKeyword(node.returnType.typeAnnotation) ||
        (!allowNull && isTSNullKeyword(node.returnType.typeAnnotation)) ||
        (!allowUndefined && isTSUndefinedKeyword(node.returnType.typeAnnotation))) {
        return {
            context,
            descriptors: [{ node: node.returnType, messageId: "generic" }],
        };
    }
    return {
        context,
        descriptors: [],
    };
}
// Create the rule.
const rule$9 = createRule(name$9, meta$a, defaultOptions$9, {
    ArrowFunctionExpression: checkFunction$2,
    FunctionDeclaration: checkFunction$2,
    FunctionExpression: checkFunction$2,
    TSCallSignatureDeclaration: checkFunction$2,
    TSConstructSignatureDeclaration: checkFunction$2,
    TSDeclareFunction: checkFunction$2,
    TSEmptyBodyFunctionExpression: checkFunction$2,
    TSFunctionType: checkFunction$2,
    TSMethodSignature: checkFunction$2,
});

/**
 * The name of this rule.
 */
const name$8 = "no-this-expressions";
/**
 * The full name of this rule.
 */
const fullName$4 = `${ruleNameScope}/${name$8}`;
/**
 * The schema for the rule options.
 */
const schema$8 = [];
/**
 * The default options for the rule.
 */
const defaultOptions$8 = [{}];
/**
 * The possible error messages.
 */
const errorMessages$8 = {
    generic: "Unexpected this, use functions not classes.",
};
/**
 * The meta data for this rule.
 */
const meta$9 = {
    type: "suggestion",
    docs: {
        category: "No Other Paradigms",
        description: "Disallow this access.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: false,
    },
    messages: errorMessages$8,
    schema: schema$8,
};
/**
 * Check if the given ThisExpression violates this rule.
 */
function checkThisExpression(node, context) {
    // All throw statements violate this rule.
    return { context, descriptors: [{ node, messageId: "generic" }] };
}
// Create the rule.
const rule$8 = createRule(name$8, meta$9, defaultOptions$8, {
    ThisExpression: checkThisExpression,
});

/**
 * The name of this rule.
 */
const name$7 = "no-throw-statements";
/**
 * The full name of this rule.
 */
const fullName$3 = `${ruleNameScope}/${name$7}`;
/**
 * The schema for the rule options.
 */
const schema$7 = [
    {
        type: "object",
        properties: {
            allowToRejectPromises: {
                type: "boolean",
            },
        },
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$7 = [
    {
        allowToRejectPromises: false,
    },
];
/**
 * The possible error messages.
 */
const errorMessages$7 = {
    generic: "Unexpected throw, throwing exceptions is not functional.",
};
/**
 * The meta data for this rule.
 */
const meta$8 = {
    type: "suggestion",
    docs: {
        category: "No Exceptions",
        description: "Disallow throwing exceptions.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: false,
    },
    messages: errorMessages$7,
    schema: schema$7,
};
/**
 * Check if the given ThrowStatement violates this rule.
 */
function checkThrowStatement(node, context, options) {
    const [{ allowToRejectPromises }] = options;
    if (!allowToRejectPromises) {
        return { context, descriptors: [{ node, messageId: "generic" }] };
    }
    if (isInPromiseHandlerFunction(node, context)) {
        return { context, descriptors: [] };
    }
    const enclosingFunction = getEnclosingFunction(node);
    if (enclosingFunction?.async !== true) {
        return { context, descriptors: [{ node, messageId: "generic" }] };
    }
    const enclosingTryStatement = getEnclosingTryStatement(node);
    if (!(enclosingTryStatement === null ||
        getEnclosingFunction(enclosingTryStatement) !== enclosingFunction ||
        enclosingTryStatement.handler === null)) {
        return { context, descriptors: [{ node, messageId: "generic" }] };
    }
    return {
        context,
        descriptors: [],
    };
}
// Create the rule.
const rule$7 = createRule(name$7, meta$8, defaultOptions$7, {
    ThrowStatement: checkThrowStatement,
});

/**
 * The name of this rule.
 */
const name$6 = "no-try-statements";
/**
 * The full name of this rule.
 */
const fullName$2 = `${ruleNameScope}/${name$6}`;
/**
 * The schema for the rule options.
 */
const schema$6 = [
    {
        type: "object",
        properties: {
            allowCatch: {
                type: "boolean",
            },
            allowFinally: {
                type: "boolean",
            },
        },
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$6 = [
    {
        allowCatch: false,
        allowFinally: false,
    },
];
/**
 * The possible error messages.
 */
const errorMessages$6 = {
    catch: "Unexpected try-catch, this pattern is not functional.",
    finally: "Unexpected try-finally, this pattern is not functional.",
};
/**
 * The meta data for this rule.
 */
const meta$7 = {
    type: "suggestion",
    docs: {
        category: "No Exceptions",
        description: "Disallow try-catch[-finally] and try-finally patterns.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: false,
    },
    messages: errorMessages$6,
    schema: schema$6,
};
/**
 * Check if the given TryStatement violates this rule.
 */
function checkTryStatement(node, context, options) {
    const [{ allowCatch, allowFinally }] = options;
    return {
        context,
        descriptors: !allowCatch && node.handler !== null
            ? [{ node, messageId: "catch" }]
            : !allowFinally && node.finalizer !== null
                ? [{ node, messageId: "finally" }]
                : [],
    };
}
// Create the rule.
const rule$6 = createRule(name$6, meta$7, defaultOptions$6, {
    TryStatement: checkTryStatement,
});

/**
 * The name of this rule.
 */
const name$5 = "prefer-immutable-types";
/**
 * The full name of this rule.
 */
const fullName$1 = `${ruleNameScope}/${name$5}`;
/**
 * The enum options for the level of enforcement.
 */
const enforcementEnumOptions = [
    ...Object.values(Immutability).filter((i) => i !== Immutability.Unknown &&
        i !== Immutability[Immutability.Unknown] &&
        i !== Immutability.Mutable &&
        i !== Immutability[Immutability.Mutable]),
    "None",
    false,
];
/**
 * The non-shorthand schema for each option.
 */
const optionExpandedSchema = deepmerge(ignoreClassesOptionSchema, {
    enforcement: {
        type: ["string", "number", "boolean"],
        enum: enforcementEnumOptions,
    },
    ignoreInferredTypes: {
        type: "boolean",
    },
    ignoreNamePattern: {
        type: ["string", "array"],
        items: {
            type: "string",
        },
    },
    ignoreTypePattern: {
        type: ["string", "array"],
        items: {
            type: "string",
        },
    },
});
/**
 * The schema for each option.
 */
const optionSchema = {
    oneOf: [
        {
            type: "object",
            properties: optionExpandedSchema,
            additionalProperties: false,
        },
        {
            type: ["string", "number", "boolean"],
            enum: enforcementEnumOptions,
        },
    ],
};
/**
 * The schema for each fixer config.
 */
const fixerSchema$1 = {
    oneOf: [
        {
            type: "object",
            properties: {
                pattern: { type: "string" },
                replace: { type: "string" },
            },
            additionalProperties: false,
        },
        {
            type: "array",
            items: {
                type: "object",
                properties: {
                    pattern: { type: "string" },
                    replace: { type: "string" },
                },
                additionalProperties: false,
            },
        },
    ],
};
const suggestionsSchema$1 = {
    type: "array",
    items: {
        type: "array",
        items: {
            type: "object",
            properties: {
                pattern: { type: "string" },
                replace: { type: "string" },
                message: { type: "string" },
            },
            additionalProperties: false,
        },
    },
};
const coreOptionsPropertiesSchema = deepmerge(optionExpandedSchema, {
    parameters: optionSchema,
    returnTypes: optionSchema,
    variables: {
        oneOf: [
            {
                type: "object",
                properties: deepmerge(optionExpandedSchema, {
                    ignoreInFunctions: {
                        type: "boolean",
                    },
                }),
                additionalProperties: false,
            },
            {
                type: ["string", "number", "boolean"],
                enum: enforcementEnumOptions,
            },
        ],
    },
    fixer: {
        type: "object",
        properties: {
            ReadonlyShallow: fixerSchema$1,
            ReadonlyDeep: fixerSchema$1,
            Immutable: fixerSchema$1,
        },
        additionalProperties: false,
    },
    suggestions: {
        type: "object",
        properties: {
            ReadonlyShallow: suggestionsSchema$1,
            ReadonlyDeep: suggestionsSchema$1,
            Immutable: suggestionsSchema$1,
        },
        additionalProperties: false,
    },
});
/**
 * The schema for the rule options.
 */
const schema$5 = [overridableOptionsSchema(coreOptionsPropertiesSchema)];
/**
 * The default options for the rule.
 */
const defaultOptions$5 = [
    {
        enforcement: Immutability.Immutable,
        ignoreInferredTypes: false,
        ignoreClasses: false,
        suggestions: {
            ReadonlyShallow: [
                [
                    {
                        pattern: "^([_$a-zA-Z\\xA0-\\uFFFF][_$a-zA-Z0-9\\xA0-\\uFFFF]*\\[\\])$",
                        replace: "readonly $1",
                        message: "Prepend with readonly.",
                    },
                    {
                        pattern: "^(Array|Map|Set)<(.+)>$",
                        replace: "Readonly$1<$2>",
                        message: "Use Readonly$1 instead of $1.",
                    },
                ],
                [
                    {
                        pattern: "^(.+)$",
                        replace: "Readonly<$1>",
                        message: "Surround with Readonly.",
                    },
                ],
            ],
        },
    },
];
/**
 * The possible error messages.
 */
const errorMessages$5 = {
    parameter: 'Parameter should have an immutability of at least "{{ expected }}" (actual: "{{ actual }}").',
    returnType: 'Return type should have an immutability of at least "{{ expected }}" (actual: "{{ actual }}").',
    variable: 'Variable should have an immutability of at least "{{ expected }}" (actual: "{{ actual }}").',
    propertyImmutability: 'Property should have an immutability of at least "{{ expected }}" (actual: "{{ actual }}").',
    propertyModifier: "Property should have a readonly modifier.",
    propertyModifierSuggestion: "Add readonly modifier.",
    userDefined: "{{ message }}",
};
/**
 * The meta data for this rule.
 */
const meta$6 = {
    type: "suggestion",
    docs: {
        category: "No Mutations",
        description: "Require function parameters to be typed as certain immutability",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: true,
    },
    fixable: "code",
    hasSuggestions: true,
    messages: errorMessages$5,
    schema: schema$5,
};
/**
 * Get the fixer and the suggestions' fixers.
 */
function getAllFixers(node, context, fixerConfigs, suggestionsConfigs) {
    const nodeText = context.sourceCode.getText(node).replaceAll(/\s+/gu, " ");
    const fix = fixerConfigs === false ? null : getConfiguredFixer$1(node, nodeText, fixerConfigs);
    const suggestionFixers = suggestionsConfigs === false ? null : getConfiguredSuggestionFixers(node, nodeText, suggestionsConfigs);
    return { fix, suggestionFixers };
}
/**
 * Get a fixer that uses the user config.
 */
function getConfiguredFixer$1(node, text, configs) {
    const config = configs.find((c) => c.pattern.test(text));
    if (config === undefined) {
        return null;
    }
    return (fixer) => fixer.replaceText(node, text.replace(config.pattern, config.replace));
}
/**
 * Get a fixer that uses the user config.
 */
function getConfiguredSuggestionFixers(node, text, suggestionsConfigs) {
    return suggestionsConfigs
        .map((configs) => {
        const config = configs.find((c) => c.pattern.test(text));
        if (config === undefined) {
            return null;
        }
        return {
            fix: (fixer) => fixer.replaceText(node, text.replace(config.pattern, config.replace)),
            message: config.message === undefined
                ? `Replace with: ${text.replace(config.pattern, config.replace)}`
                : text.replace(config.pattern, config.message),
        };
    })
        .filter(isDefined);
}
/**
 * Get the level of enforcement from the raw value given.
 */
function parseEnforcement(rawEnforcement) {
    return rawEnforcement === "None" || rawEnforcement === undefined
        ? false
        : typeof rawEnforcement === "string"
            ? Immutability[rawEnforcement]
            : rawEnforcement;
}
/**
 * Get the fixer config for the the given enforcement level from the raw config given.
 */
function parseFixerConfigs(allRawConfigs, enforcement) {
    const key = Immutability[enforcement];
    const rawConfigs = allRawConfigs?.[key];
    if (rawConfigs === undefined) {
        return false;
    }
    const raws = Array.isArray(rawConfigs) ? rawConfigs : [rawConfigs];
    return raws.map((r) => ({
        ...r,
        pattern: new RegExp(r.pattern, "u"),
    }));
}
/**
 * Get the suggestions config for the the given enforcement level from the raw config given.
 */
function parseSuggestionsConfigs(rawSuggestions, enforcement) {
    const key = Immutability[enforcement];
    const rawConfigsSet = rawSuggestions?.[key];
    if (rawConfigsSet === undefined) {
        return false;
    }
    return rawConfigsSet.map((rawConfigs) => rawConfigs.map((rawConfig) => ({
        ...rawConfig,
        pattern: new RegExp(rawConfig.pattern, "u"),
    })));
}
/**
 * Get the parameter type violations.
 */
function getParameterTypeViolations(node, context, options) {
    return node.params
        .map((param) => {
        const parameterProperty = isTSParameterProperty(param);
        const actualParam = parameterProperty ? param.parameter : param;
        const optionsToUse = getOptionsWithDefaults(getCoreOptions(param, context, options));
        if (optionsToUse === null) {
            return undefined;
        }
        const { parameters: rawOption, fixer: rawFixerConfig, suggestions: rawSuggestionsConfigs } = optionsToUse;
        const { enforcement: rawEnforcement, ignoreInferredTypes, ignoreClasses, ignoreNamePattern, ignoreTypePattern, } = {
            ignoreInferredTypes: optionsToUse.ignoreInferredTypes,
            ignoreClasses: optionsToUse.ignoreClasses,
            ignoreNamePattern: optionsToUse.ignoreNamePattern,
            ignoreTypePattern: optionsToUse.ignoreTypePattern,
            ...(typeof rawOption === "object"
                ? rawOption
                : {
                    enforcement: rawOption,
                }),
        };
        const enforcement = parseEnforcement(rawEnforcement ?? optionsToUse.enforcement);
        if (enforcement === false || shouldIgnoreClasses(node, context, ignoreClasses)) {
            return undefined;
        }
        const fixerConfigs = parseFixerConfigs(rawFixerConfig, enforcement);
        const suggestionsConfigs = parseSuggestionsConfigs(rawSuggestionsConfigs, enforcement);
        if (shouldIgnorePattern(param, context, ignoreNamePattern)) {
            return undefined;
        }
        if (parameterProperty && !param.readonly) {
            const fix = (fixer) => fixer.insertTextBefore(param.parameter, "readonly ");
            return {
                node: param,
                messageId: "propertyModifier",
                fix: fixerConfigs === false ? null : fix,
                suggest: [
                    {
                        messageId: "propertyModifierSuggestion",
                        fix,
                    },
                ],
            };
        }
        if (
        // inferred types
        (ignoreInferredTypes && actualParam.typeAnnotation === undefined) ||
            // ignored
            (actualParam.typeAnnotation !== undefined &&
                shouldIgnorePattern(actualParam.typeAnnotation, context, ignoreTypePattern)) ||
            // type guard
            (node.returnType !== undefined &&
                isTSTypePredicate(node.returnType.typeAnnotation) &&
                isIdentifier(node.returnType.typeAnnotation.parameterName) &&
                isIdentifier(actualParam) &&
                actualParam.name === node.returnType.typeAnnotation.parameterName.name)) {
            return undefined;
        }
        const immutability = getTypeImmutabilityOfNode(actualParam, context, enforcement);
        if (immutability >= enforcement) {
            return undefined;
        }
        const { fix, suggestionFixers } = actualParam.typeAnnotation === undefined
            ? {}
            : getAllFixers(actualParam.typeAnnotation.typeAnnotation, context, fixerConfigs, suggestionsConfigs);
        return {
            node: actualParam,
            messageId: "parameter",
            data: {
                actual: Immutability[immutability],
                expected: Immutability[enforcement],
            },
            fix,
            suggest: suggestionFixers?.map(({ fix, message }) => ({
                messageId: "userDefined",
                data: {
                    message,
                },
                fix,
            })) ?? null,
        };
    })
        .filter(isDefined);
}
/**
 * Get the return type violations.
 */
function getReturnTypeViolations(node, context, options) {
    function getOptions(type, typeNode) {
        const optionsToUse = getOptionsWithDefaults(getCoreOptionsForType(type, typeNode, context, options));
        if (optionsToUse === null) {
            return null;
        }
        const { returnTypes: rawOption, fixer: rawFixerConfig, suggestions: rawSuggestionsConfigs } = optionsToUse;
        const { enforcement: rawEnforcement, ignoreClasses, ignoreNamePattern, ignoreTypePattern, ignoreInferredTypes, } = {
            ignoreClasses: optionsToUse.ignoreClasses,
            ignoreNamePattern: optionsToUse.ignoreNamePattern,
            ignoreTypePattern: optionsToUse.ignoreTypePattern,
            ignoreInferredTypes: optionsToUse.ignoreInferredTypes,
            ...(typeof rawOption === "object" ? rawOption : { enforcement: rawOption }),
        };
        const enforcement = parseEnforcement(rawEnforcement ?? optionsToUse.enforcement);
        if (enforcement === false ||
            shouldIgnoreClasses(node, context, ignoreClasses) ||
            shouldIgnorePattern(node, context, ignoreNamePattern)) {
            return null;
        }
        const fixerConfigs = parseFixerConfigs(rawFixerConfig, enforcement);
        const suggestionsConfigs = parseSuggestionsConfigs(rawSuggestionsConfigs, enforcement);
        return {
            ignoreTypePattern,
            ignoreInferredTypes,
            enforcement,
            fixerConfigs,
            suggestionsConfigs,
        };
    }
    if (node.returnType?.typeAnnotation !== undefined) {
        const [type, typeNode] = getTypeDataOfNode(node, context);
        const optionsToUse = getOptions(type, typeNode);
        if (optionsToUse === null) {
            return [];
        }
        const { ignoreTypePattern, enforcement, fixerConfigs, suggestionsConfigs } = optionsToUse;
        if (node.returnType?.typeAnnotation !== undefined && !isTSTypePredicate(node.returnType.typeAnnotation)) {
            if (shouldIgnorePattern(node.returnType, context, ignoreTypePattern)) {
                return [];
            }
            const immutability = getTypeImmutabilityOfNode(node.returnType.typeAnnotation, context, enforcement);
            if (immutability >= enforcement) {
                return [];
            }
            const { fix, suggestionFixers } = getAllFixers(node.returnType.typeAnnotation, context, fixerConfigs, suggestionsConfigs);
            return [
                {
                    node: node.returnType,
                    messageId: "returnType",
                    data: {
                        actual: Immutability[immutability],
                        expected: Immutability[enforcement],
                    },
                    fix,
                    suggest: suggestionFixers?.map(({ fix, message }) => ({
                        messageId: "userDefined",
                        data: {
                            message,
                        },
                        fix,
                    })) ?? null,
                },
            ];
        }
    }
    if (!isFunctionLike(node)) {
        return [];
    }
    const returnTypes = getReturnTypesOfFunction(node, context);
    if (returnTypes === null || returnTypes.length !== 1 || isImplementationOfOverload(node, context)) {
        return [];
    }
    const returnType = returnTypes[0];
    const optionsToUse = getOptions(returnType, returnType.node ?? null);
    if (optionsToUse === null) {
        return [];
    }
    const { ignoreInferredTypes, enforcement, fixerConfigs, suggestionsConfigs } = optionsToUse;
    if (ignoreInferredTypes) {
        return [];
    }
    const immutability = getTypeImmutabilityOfType(returnType, context, enforcement);
    if (immutability >= enforcement) {
        return [];
    }
    const { fix, suggestionFixers } = node.returnType?.typeAnnotation === undefined
        ? {}
        : getAllFixers(node.returnType.typeAnnotation, context, fixerConfigs, suggestionsConfigs);
    return [
        {
            node: hasID(node) && node.id !== null ? node.id : node,
            messageId: "returnType",
            data: {
                actual: Immutability[immutability],
                expected: Immutability[enforcement],
            },
            fix,
            suggest: suggestionFixers?.map(({ fix, message }) => ({
                messageId: "userDefined",
                data: {
                    message,
                },
                fix,
            })) ?? null,
        },
    ];
}
/**
 * Add the default options to the given options.
 */
function getOptionsWithDefaults(options) {
    if (options === null) {
        return null;
    }
    return {
        ...defaultOptions$5[0],
        ...options,
    };
}
/**
 * Check if the given function node violates this rule.
 */
function checkFunction$1(node, context, rawOptions) {
    const options = upgradeRawOverridableOptions(rawOptions[0]);
    const descriptors = [
        ...getParameterTypeViolations(node, context, options),
        ...getReturnTypeViolations(node, context, options),
    ];
    return {
        context,
        descriptors,
    };
}
/**
 * Check if the given function node violates this rule.
 */
function checkVariable(node, context, rawOptions) {
    const options = upgradeRawOverridableOptions(rawOptions[0]);
    const optionsToUse = getOptionsWithDefaults(getCoreOptions(node, context, options));
    if (optionsToUse === null) {
        return {
            context,
            descriptors: [],
        };
    }
    const { variables: rawOption, fixer: rawFixerConfig, suggestions: rawSuggestionsConfigs } = optionsToUse;
    const { enforcement: rawEnforcement, ignoreInferredTypes, ignoreClasses, ignoreNamePattern, ignoreTypePattern, ignoreInFunctions, } = {
        ignoreInferredTypes: optionsToUse.ignoreInferredTypes,
        ignoreClasses: optionsToUse.ignoreClasses,
        ignoreNamePattern: optionsToUse.ignoreNamePattern,
        ignoreTypePattern: optionsToUse.ignoreTypePattern,
        ignoreInFunctions: false,
        ...(typeof rawOption === "object" ? rawOption : { enforcement: rawOption }),
    };
    const enforcement = parseEnforcement(rawEnforcement ?? optionsToUse.enforcement);
    if (enforcement === false ||
        shouldIgnoreClasses(node, context, ignoreClasses) ||
        shouldIgnoreInFunction(node, context, ignoreInFunctions) ||
        shouldIgnorePattern(node, context, ignoreNamePattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    const propertyDefinition = isPropertyDefinition(node);
    if (propertyDefinition && !node.readonly) {
        const fix = (fixer) => fixer.insertTextBefore(node.key, "readonly ");
        return {
            context,
            descriptors: [
                {
                    node,
                    messageId: "propertyModifier",
                    fix: rawFixerConfig === undefined ? null : fix,
                    suggest: [
                        {
                            messageId: "propertyModifierSuggestion",
                            fix,
                        },
                    ],
                },
            ],
        };
    }
    const nodeWithTypeAnnotation = propertyDefinition ? node : node.id;
    if (ignoreInferredTypes && nodeWithTypeAnnotation.typeAnnotation === undefined) {
        return {
            context,
            descriptors: [],
        };
    }
    if (nodeWithTypeAnnotation.typeAnnotation !== undefined &&
        shouldIgnorePattern(nodeWithTypeAnnotation.typeAnnotation, context, ignoreTypePattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    const elements = isArrayPattern(nodeWithTypeAnnotation)
        ? nodeWithTypeAnnotation.elements
        : isObjectPattern(nodeWithTypeAnnotation)
            ? nodeWithTypeAnnotation.properties
            : [nodeWithTypeAnnotation];
    const elementResults = elements.map((element) => {
        if (!isDefined(element)) {
            return null;
        }
        const immutability = getTypeImmutabilityOfNode(element, context, enforcement);
        if (immutability >= enforcement) {
            return null;
        }
        const fixerConfigs = parseFixerConfigs(rawFixerConfig, enforcement);
        const suggestionsConfigs = parseSuggestionsConfigs(rawSuggestionsConfigs, enforcement);
        const { fix, suggestionFixers } = isMemberExpression(element) || isProperty(element) || element.typeAnnotation === undefined
            ? {}
            : getAllFixers(element.typeAnnotation.typeAnnotation, context, fixerConfigs, suggestionsConfigs);
        return { element, immutability, fix, suggestionFixers };
    });
    const messageId = propertyDefinition ? "propertyImmutability" : "variable";
    return {
        context,
        descriptors: elementResults.filter(isDefined).map(({ element, immutability, fix, suggestionFixers }) => {
            const data = {
                actual: Immutability[immutability],
                expected: Immutability[enforcement],
            };
            return {
                node: element,
                messageId,
                data,
                fix,
                suggest: suggestionFixers?.map(({ fix, message }) => ({
                    messageId: "userDefined",
                    data: {
                        message,
                    },
                    fix,
                })) ?? null,
            };
        }),
    };
}
// Create the rule.
const rule$5 = createRule(name$5, meta$6, defaultOptions$5, {
    ArrowFunctionExpression: checkFunction$1,
    FunctionDeclaration: checkFunction$1,
    FunctionExpression: checkFunction$1,
    TSCallSignatureDeclaration: checkFunction$1,
    TSConstructSignatureDeclaration: checkFunction$1,
    TSDeclareFunction: checkFunction$1,
    TSEmptyBodyFunctionExpression: checkFunction$1,
    TSFunctionType: checkFunction$1,
    TSMethodSignature: checkFunction$1,
    PropertyDefinition: checkVariable,
    VariableDeclarator: checkVariable,
});

/**
 * The name of this rule.
 */
const name$4 = "prefer-property-signatures";
/**
 * The schema for the rule options.
 */
const schema$4 = [
    {
        type: "object",
        properties: {
            ignoreIfReadonlyWrapped: {
                type: "boolean",
                default: false,
            },
        },
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$4 = [
    {
        ignoreIfReadonlyWrapped: false,
    },
];
/**
 * The possible error messages.
 */
const errorMessages$4 = {
    generic: "Use a property signature instead of a method signature",
};
/**
 * The meta data for this rule.
 */
const meta$5 = {
    type: "suggestion",
    docs: {
        category: "Stylistic",
        description: "Prefer property signatures over method signatures.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: true,
    },
    messages: errorMessages$4,
    schema: schema$4,
};
/**
 * Check if the given TSMethodSignature violates this rule.
 */
function checkTSMethodSignature(node, context, options) {
    const [{ ignoreIfReadonlyWrapped }] = options;
    if (ignoreIfReadonlyWrapped && isInReadonly(node)) {
        return { context, descriptors: [] };
    }
    // All TS method signatures violate this rule.
    return { context, descriptors: [{ node, messageId: "generic" }] };
}
// Create the rule.
const rule$4 = createRule(name$4, meta$5, defaultOptions$4, {
    TSMethodSignature: checkTSMethodSignature,
});

/**
 * The name of this rule.
 */
const name$3 = "prefer-readonly-type";
/**
 * The schema for the rule options.
 */
const schema$3 = [
    {
        type: "object",
        properties: {
            allowLocalMutation: {
                type: "boolean",
            },
            ignorePattern: {
                type: ["string", "array"],
                items: {
                    type: "string",
                },
            },
            ignoreClass: {
                oneOf: [
                    {
                        type: "boolean",
                    },
                    {
                        type: "string",
                        enum: ["fieldsOnly"],
                    },
                ],
            },
            ignoreInterface: {
                type: "boolean",
            },
            allowMutableReturnType: {
                type: "boolean",
            },
            checkImplicit: {
                type: "boolean",
            },
            ignoreCollections: {
                type: "boolean",
            },
        },
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$3 = [
    {
        checkImplicit: false,
        ignoreClass: false,
        ignoreInterface: false,
        ignoreCollections: false,
        allowLocalMutation: false,
        allowMutableReturnType: false,
    },
];
/**
 * The possible error messages.
 */
const errorMessages$3 = {
    array: "Only readonly arrays allowed.",
    implicit: "Implicitly a mutable array. Only readonly arrays allowed.",
    property: "A readonly modifier is required.",
    tuple: "Only readonly tuples allowed.",
    type: "Only readonly types allowed.",
};
/**
 * The meta data for this rule.
 */
const meta$4 = {
    deprecated: true,
    replacedBy: ["functional/prefer-immutable-types", "functional/type-declaration-immutability"],
    type: "suggestion",
    docs: {
        category: "No Mutations",
        description: "Prefer readonly types over mutable types.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: true,
    },
    messages: errorMessages$3,
    fixable: "code",
    schema: schema$3,
};
const mutableToImmutableTypes = new Map([
    ["Array", "ReadonlyArray"],
    ["Map", "ReadonlyMap"],
    ["Set", "ReadonlySet"],
]);
const mutableTypeRegex = new RegExp(`^${[...mutableToImmutableTypes.keys()].join("|")}$`, "u");
/**
 * For backwards compatibility.
 */
function shouldIgnorePattern2(node, context, ignorePattern, ignoreAccessorPattern) {
    const isTypeNode = isTSArrayType(node) ||
        isTSIndexSignature(node) ||
        isTSTupleType(node) ||
        isTSTypeAnnotation(node) ||
        isTSTypeLiteral(node) ||
        isTSTypeReference(node);
    if (isTypeNode) {
        return shouldIgnorePattern2(node.parent, context, ignorePattern, ignoreAccessorPattern);
    }
    return shouldIgnorePattern(node, context, ignorePattern, ignoreAccessorPattern);
}
/**
 * Check if the given ArrayType or TupleType violates this rule.
 */
function checkArrayOrTupleType(node, context, options) {
    const [optionsObject] = options;
    const { allowLocalMutation, allowMutableReturnType, ignoreClass, ignoreCollections, ignoreInterface, ignorePattern } = optionsObject;
    if (shouldIgnoreClasses(node, context, ignoreClass) ||
        (ignoreInterface && isInInterface(node)) ||
        shouldIgnoreInFunction(node, context, allowLocalMutation) ||
        shouldIgnorePattern2(node, context, ignorePattern) ||
        ignoreCollections) {
        return {
            context,
            descriptors: [],
        };
    }
    return {
        context,
        descriptors: (node.parent === undefined || !isTSTypeOperator(node.parent) || node.parent.operator !== "readonly") &&
            (!allowMutableReturnType || !isInReturnType(node))
            ? [
                {
                    node,
                    messageId: isTSTupleType(node) ? "tuple" : "array",
                    fix: node.parent !== undefined && isTSArrayType(node.parent)
                        ? (fixer) => [
                            fixer.insertTextBefore(node, "(readonly "),
                            fixer.insertTextAfter(node, ")"),
                        ]
                        : (fixer) => fixer.insertTextBefore(node, "readonly "),
                },
            ]
            : [],
    };
}
/**
 * Check if the given TSMappedType violates this rule.
 */
function checkMappedType(node, context, options) {
    const [optionsObject] = options;
    const { allowLocalMutation, ignoreClass, ignoreInterface, ignorePattern } = optionsObject;
    if (shouldIgnoreClasses(node, context, ignoreClass) ||
        (ignoreInterface && isInInterface(node)) ||
        shouldIgnoreInFunction(node, context, allowLocalMutation) ||
        shouldIgnorePattern2(node, context, ignorePattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    return {
        context,
        descriptors: node.readonly === true || node.readonly === "+"
            ? []
            : [
                {
                    node,
                    messageId: "property",
                    fix: (fixer) => fixer.insertTextBeforeRange([node.range[0] + 1, node.range[1]], " readonly"),
                },
            ],
    };
}
/**
 * Check if the given TypeReference violates this rule.
 */
function checkTypeReference(node, context, options) {
    const [optionsObject] = options;
    const { allowLocalMutation, ignoreClass, ignoreInterface, ignorePattern, allowMutableReturnType, ignoreCollections } = optionsObject;
    if (shouldIgnoreClasses(node, context, ignoreClass) ||
        (ignoreInterface && isInInterface(node)) ||
        shouldIgnoreInFunction(node, context, allowLocalMutation) ||
        shouldIgnorePattern2(node, context, ignorePattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    if (isIdentifier(node.typeName)) {
        if (ignoreCollections && mutableTypeRegex.test(node.typeName.name)) {
            return {
                context,
                descriptors: [],
            };
        }
        const immutableType = mutableToImmutableTypes.get(node.typeName.name);
        return {
            context,
            descriptors: immutableType !== undefined && immutableType.length > 0 && (!allowMutableReturnType || !isInReturnType(node))
                ? [
                    {
                        node,
                        messageId: "type",
                        fix: (fixer) => fixer.replaceText(node.typeName, immutableType),
                    },
                ]
                : [],
        };
    }
    return {
        context,
        descriptors: [],
    };
}
/**
 * Check if the given property/signature node violates this rule.
 */
function checkProperty(node, context, options) {
    const [optionsObject] = options;
    const { allowLocalMutation, ignoreClass, ignoreInterface, ignorePattern, allowMutableReturnType } = optionsObject;
    if (shouldIgnoreClasses(node, context, ignoreClass) ||
        (ignoreInterface && isInInterface(node)) ||
        shouldIgnoreInFunction(node, context, allowLocalMutation) ||
        shouldIgnorePattern2(node, context, ignorePattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    return {
        context,
        descriptors: !node.readonly && (!allowMutableReturnType || !isInReturnType(node))
            ? [
                {
                    node,
                    messageId: "property",
                    fix: isTSIndexSignature(node) || isTSPropertySignature(node)
                        ? (fixer) => fixer.insertTextBefore(node, "readonly ")
                        : isTSParameterProperty(node)
                            ? (fixer) => fixer.insertTextBefore(node.parameter, "readonly ")
                            : (fixer) => fixer.insertTextBefore(node.key, "readonly "),
                },
            ]
            : [],
    };
}
/**
 * Check if the given TypeReference violates this rule.
 */
function checkImplicitType(node, context, options) {
    const [optionsObject] = options;
    const { allowLocalMutation, ignoreClass, ignoreInterface, ignorePattern, checkImplicit, ignoreCollections } = optionsObject;
    if (!checkImplicit ||
        shouldIgnoreClasses(node, context, ignoreClass) ||
        (ignoreInterface && isInInterface(node)) ||
        shouldIgnoreInFunction(node, context, allowLocalMutation) ||
        shouldIgnorePattern2(node, context, ignorePattern)) {
        return {
            context,
            descriptors: [],
        };
    }
    const declarators = isFunctionLike(node)
        ? node.params
            .map((param) => isAssignmentPattern(param)
            ? {
                id: param.left,
                init: param.right,
                node: param,
            }
            : undefined)
            .filter((param) => param !== undefined)
        : node.declarations.map((declaration) => ({
            id: declaration.id,
            init: declaration.init,
            node: declaration,
        }));
    return {
        context,
        descriptors: declarators.flatMap((declarator) => isIdentifier(declarator.id) &&
            declarator.id.typeAnnotation === undefined &&
            declarator.init !== null &&
            isArrayType(context, getTypeOfNode(declarator.init, context)) &&
            !ignoreCollections
            ? [
                {
                    node: declarator.node,
                    messageId: "implicit",
                    fix: (fixer) => fixer.insertTextAfter(declarator.id, ": readonly unknown[]"),
                },
            ]
            : []),
    };
}
// Create the rule.
const rule$3 = createRule(name$3, meta$4, defaultOptions$3, {
    ArrowFunctionExpression: checkImplicitType,
    PropertyDefinition: checkProperty,
    FunctionDeclaration: checkImplicitType,
    FunctionExpression: checkImplicitType,
    TSArrayType: checkArrayOrTupleType,
    TSIndexSignature: checkProperty,
    TSParameterProperty: checkProperty,
    TSPropertySignature: checkProperty,
    TSTupleType: checkArrayOrTupleType,
    TSMappedType: checkMappedType,
    TSTypeReference: checkTypeReference,
    VariableDeclaration: checkImplicitType,
});

/**
 * The name of this rule.
 */
const name$2 = "prefer-tacit";
/**
 * The schema for the rule options.
 */
const schema$2 = [
    {
        type: "object",
        properties: {
            checkMemberExpressions: {
                type: "boolean",
            },
        },
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$2 = [
    {
        checkMemberExpressions: false,
    },
];
/**
 * The possible error messages.
 */
const errorMessages$2 = {
    generic: "Potentially unnecessary function wrapper.",
    genericSuggestion: "Remove unnecessary function wrapper.",
};
/**
 * The meta data for this rule.
 */
const meta$3 = {
    type: "suggestion",
    docs: {
        category: "Stylistic",
        description: "Replaces `x => f(x)` with just `f`.",
        recommended: "recommended",
        recommendedSeverity: "warn",
        requiresTypeChecking: true,
    },
    messages: errorMessages$2,
    hasSuggestions: true,
    schema: schema$2,
};
/**
 * From the callee's type, does it follow that the caller violates this rule.
 */
function isCallerViolation(caller, calleeType, context) {
    if (calleeType.symbol === undefined) {
        return false;
    }
    const tsDeclaration = calleeType.symbol.valueDeclaration ?? calleeType.symbol.declarations?.[0];
    if (tsDeclaration === undefined) {
        return false;
    }
    return getTypeOfTSNode(tsDeclaration, context)
        .getCallSignatures()
        .some((signature) => signature.parameters.length === caller.arguments.length);
}
/**
 * Get the fixes for a call to a reference violation.
 */
function fixFunctionCallToReference(context, fixer, node, caller) {
    // Fix to Instantiation Expression.
    if (caller.typeArguments !== undefined && caller.typeArguments.params.length > 0) {
        return [
            fixer.removeRange([node.range[0], caller.callee.range[0]]),
            fixer.removeRange([caller.typeArguments.range[1], node.range[1]]),
        ];
    }
    return [
        fixer.replaceText(node, isMemberExpression(caller.callee)
            ? `${context.sourceCode.getText(caller.callee)}.bind(${context.sourceCode.getText(caller.callee.object)})`
            : context.sourceCode.getText(caller.callee)),
    ];
}
/**
 * Creates the suggestions.
 */
function buildSuggestions(context, node, caller) {
    return [
        {
            messageId: "genericSuggestion",
            fix: (fixer) => {
                const functionCallToReference = fixFunctionCallToReference(context, fixer, node, caller);
                if (functionCallToReference === null) {
                    return null;
                }
                if (node.type === TSESTree.AST_NODE_TYPES.FunctionDeclaration && !isNested(node)) {
                    if (node.id === null) {
                        return null;
                    }
                    return [
                        fixer.insertTextBefore(node, `const ${node.id.name} = `),
                        fixer.insertTextAfter(node, `;`),
                        ...functionCallToReference,
                    ];
                }
                return functionCallToReference;
            },
        },
    ];
}
/**
 * Check for violations based on the given caller.
 */
function getCallDescriptors(node, context, options, caller) {
    const [{ checkMemberExpressions }] = options;
    if (!isIdentifier(caller.callee) && !(checkMemberExpressions && isMemberExpression(caller.callee))) {
        return [];
    }
    if (node.params.length === caller.arguments.length &&
        node.params.every((param, index) => {
            const callArg = caller.arguments[index];
            return isIdentifier(callArg) && isIdentifier(param) && callArg.name === param.name;
        })) {
        const calleeType = getTypeOfNode(caller.callee, context);
        if (calleeType !== null && isCallerViolation(caller, calleeType, context)) {
            return [
                {
                    node,
                    messageId: "generic",
                    suggest: buildSuggestions(context, node, caller),
                },
            ];
        }
        return [];
    }
    return [];
}
/**
 * Check for violations in the form: `x => f(x)`.
 */
function getDirectCallDescriptors(node, context, options) {
    if (isCallExpression(node.body)) {
        return getCallDescriptors(node, context, options, node.body);
    }
    return [];
}
/**
 * Check for violations in the form: `x => { return f(x); }`.
 */
function getNestedCallDescriptors(node, context, options) {
    if (isBlockStatement(node.body) &&
        node.body.body.length === 1 &&
        isReturnStatement(node.body.body[0]) &&
        node.body.body[0].argument !== null &&
        isCallExpression(node.body.body[0].argument)) {
        return getCallDescriptors(node, context, options, node.body.body[0].argument);
    }
    return [];
}
/**
 * Check if the given function node violates this rule.
 */
function checkFunction(node, context, options) {
    return {
        context,
        descriptors: [
            ...getDirectCallDescriptors(node, context, options),
            ...getNestedCallDescriptors(node, context, options),
        ],
    };
}
// Create the rule.
const rule$2 = createRule(name$2, meta$3, defaultOptions$2, {
    FunctionDeclaration: checkFunction,
    FunctionExpression: checkFunction,
    ArrowFunctionExpression: checkFunction,
});

/**
 * The name of this rule.
 */
const name$1 = "readonly-type";
/**
 * The schema for the rule options.
 */
const schema$1 = [
    {
        type: "string",
        enum: ["generic", "keyword"],
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions$1 = ["generic"];
/**
 * The possible error messages.
 */
const errorMessages$1 = {
    generic: "Readonly type using 'readonly' keyword is forbidden. Use 'Readonly<T>' instead.",
    keyword: "Readonly type using 'Readonly<T>' is forbidden. Use 'readonly' keyword instead.",
};
/**
 * The meta data for this rule.
 */
const meta$2 = {
    type: "suggestion",
    docs: {
        category: "Stylistic",
        description: "Require consistently using either `readonly` keywords or `Readonly<T>`",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: true,
    },
    fixable: "code",
    messages: errorMessages$1,
    schema: schema$1,
};
/**
 * Check for violations with a type literal.
 */
function checkTypeLiteral(node, context, options) {
    const [mode] = options;
    const readonlyWrapper = getReadonly(node);
    const { sourceCode } = context;
    if (readonlyWrapper !== null) {
        if (mode === "generic") {
            return {
                context,
                descriptors: node.members
                    .map((member) => {
                    if ((isPropertyDefinition(member) || isTSParameterProperty(member) || isTSPropertySignature(member)) &&
                        member.readonly) {
                        return {
                            node: member.key,
                            messageId: "generic",
                            fix: (fixer) => fixer.replaceText(member, sourceCode.getText(member).replace(/readonly /u, "")),
                        };
                    }
                    return undefined;
                })
                    .filter(isDefined),
            };
        }
        return {
            context,
            descriptors: [
                {
                    node: isTSTypeReference(readonlyWrapper) ? readonlyWrapper.typeName : readonlyWrapper,
                    messageId: "keyword",
                    fix: (fixer) => {
                        const text = sourceCode.getText(readonlyWrapper);
                        const wrapperStartPattern = /^Readonly\s*</gu;
                        const wrapperEndPattern = /\s*>$/u;
                        wrapperStartPattern.exec(text);
                        const end = wrapperEndPattern.exec(text);
                        const startCutPoint = wrapperStartPattern.lastIndex;
                        const endCutPoint = end.index;
                        return [
                            fixer.removeRange([readonlyWrapper.range[0], readonlyWrapper.range[0] + startCutPoint]),
                            fixer.removeRange([readonlyWrapper.range[1] - text.length + endCutPoint, readonlyWrapper.range[1]]),
                            ...node.members
                                .map((member) => {
                                if (!(isPropertyDefinition(member) ||
                                    isTSIndexSignature(member) ||
                                    isTSParameterProperty(member) ||
                                    isTSPropertySignature(member)) ||
                                    member.readonly) {
                                    return undefined;
                                }
                                return fixer.insertTextBefore(member, "readonly ");
                            })
                                .filter(isDefined),
                        ];
                    },
                },
            ],
        };
    }
    if (mode === "generic") {
        const needsWrapping = node.members.length > 0 &&
            node.members.every((member) => (isPropertyDefinition(member) ||
                isTSIndexSignature(member) ||
                isTSParameterProperty(member) ||
                isTSPropertySignature(member)) &&
                member.readonly);
        if (needsWrapping) {
            return {
                context,
                descriptors: [
                    {
                        node,
                        messageId: "generic",
                        fix: (fixer) => [
                            fixer.insertTextBefore(node, "Readonly<"),
                            fixer.insertTextAfter(node, ">"),
                            ...node.members.map((member) => fixer.replaceText(member, sourceCode.getText(member).replace(/readonly /u, ""))),
                        ],
                    },
                ],
            };
        }
    }
    return {
        context,
        descriptors: [],
    };
}
// Create the rule.
const rule$1 = createRule(name$1, meta$2, defaultOptions$1, {
    TSTypeLiteral: checkTypeLiteral,
});

/**
 * The name of this rule.
 */
const name = "type-declaration-immutability";
/**
 * The full name of this rule.
 */
const fullName = `${ruleNameScope}/${name}`;
/**
 * How the actual immutability should be compared to the given immutability.
 */
var RuleEnforcementComparator;
(function (RuleEnforcementComparator) {
    RuleEnforcementComparator[RuleEnforcementComparator["Less"] = -2] = "Less";
    RuleEnforcementComparator[RuleEnforcementComparator["AtMost"] = -1] = "AtMost";
    RuleEnforcementComparator[RuleEnforcementComparator["Exactly"] = 0] = "Exactly";
    RuleEnforcementComparator[RuleEnforcementComparator["AtLeast"] = 1] = "AtLeast";
    RuleEnforcementComparator[RuleEnforcementComparator["More"] = 2] = "More";
})(RuleEnforcementComparator || (RuleEnforcementComparator = {}));
/**
 * The schema for each fixer config.
 */
const fixerSchema = {
    oneOf: [
        {
            type: "boolean",
            enum: [false],
        },
        {
            type: "object",
            properties: {
                pattern: { type: "string" },
                replace: { type: "string" },
            },
            additionalProperties: false,
        },
        {
            type: "array",
            items: {
                type: "object",
                properties: {
                    pattern: { type: "string" },
                    replace: { type: "string" },
                },
                additionalProperties: false,
            },
        },
    ],
};
const suggestionsSchema = {
    oneOf: [
        {
            type: "boolean",
            enum: [false],
        },
        {
            type: "array",
            items: {
                type: "object",
                properties: {
                    pattern: { type: "string" },
                    replace: { type: "string" },
                },
                additionalProperties: false,
            },
        },
    ],
};
/**
 * The schema for the rule options.
 */
const schema = [
    {
        type: "object",
        properties: deepmerge(ignoreIdentifierPatternOptionSchema, {
            rules: {
                type: "array",
                items: {
                    type: "object",
                    properties: {
                        identifiers: {
                            type: ["string", "array"],
                            items: {
                                type: ["string"],
                            },
                        },
                        immutability: {
                            type: ["string", "number"],
                            enum: Object.values(Immutability).filter((i) => i !== Immutability.Unknown && i !== Immutability[Immutability.Unknown]),
                        },
                        comparator: {
                            type: ["string", "number"],
                            enum: Object.values(RuleEnforcementComparator),
                        },
                        fixer: fixerSchema,
                        suggestions: suggestionsSchema,
                    },
                    required: ["identifiers", "immutability"],
                    additionalProperties: false,
                },
            },
            ignoreInterfaces: {
                type: "boolean",
            },
        }),
        additionalProperties: false,
    },
];
/**
 * The default options for the rule.
 */
const defaultOptions = [
    {
        rules: [
            {
                identifiers: ["^(?!I?Mutable).+"],
                immutability: Immutability.Immutable,
                comparator: RuleEnforcementComparator.AtLeast,
            },
        ],
        ignoreInterfaces: false,
    },
];
/**
 * The possible error messages.
 */
const errorMessages = {
    Less: 'This type is declare to have an immutability less than "{{ expected }}" (actual: "{{ actual }}").',
    AtLeast: 'This type is declare to have an immutability of at least "{{ expected }}" (actual: "{{ actual }}").',
    Exactly: 'This type is declare to have an immutability of exactly "{{ expected }}" (actual: "{{ actual }}").',
    AtMost: 'This type is declare to have an immutability of at most "{{ expected }}" (actual: "{{ actual }}").',
    More: 'This type is declare to have an immutability more than "{{ expected }}" (actual: "{{ actual }}").',
    userDefined: "{{ message }}",
};
/**
 * The meta data for this rule.
 */
const meta$1 = {
    type: "suggestion",
    docs: {
        category: "No Mutations",
        description: "Enforce the immutability of types based on patterns.",
        recommended: "recommended",
        recommendedSeverity: "error",
        requiresTypeChecking: true,
    },
    messages: errorMessages,
    fixable: "code",
    hasSuggestions: true,
    schema,
};
/**
 * Get all the rules that were given and upgrade them.
 */
function getRules(options) {
    const [optionsObject] = options;
    const { rules: rulesOptions } = optionsObject;
    return rulesOptions.map((rule) => {
        const identifiers = Array.isArray(rule.identifiers)
            ? rule.identifiers.map((id) => new RegExp(id, "u"))
            : [new RegExp(rule.identifiers, "u")];
        const immutability = typeof rule.immutability === "string" ? Immutability[rule.immutability] : rule.immutability;
        const comparator = rule.comparator === undefined
            ? RuleEnforcementComparator.AtLeast
            : typeof rule.comparator === "string"
                ? RuleEnforcementComparator[rule.comparator]
                : rule.comparator;
        const fixers = rule.fixer === undefined || rule.fixer === false
            ? false
            : (Array.isArray(rule.fixer) ? rule.fixer : [rule.fixer]).map((r) => ({
                ...r,
                pattern: new RegExp(r.pattern, "su"),
            }));
        const suggestions = rule.suggestions === undefined || rule.suggestions === false
            ? false
            : rule.suggestions.map((r) => ({
                ...r,
                pattern: new RegExp(r.pattern, "su"),
            }));
        return {
            identifiers,
            immutability,
            comparator,
            fixers,
            suggestions,
        };
    });
}
/**
 * Find the first rule to apply to the given node.
 */
function getRuleToApply(node, context, options) {
    const rules = getRules(options);
    if (rules.length === 0) {
        return undefined;
    }
    const texts = getNodeIdentifierTexts(node, context);
    if (texts.length === 0) {
        return undefined;
    }
    return rules.find((rule) => rule.identifiers.some((pattern) => texts.some((text) => pattern.test(text))));
}
/**
 * Get a fixer that uses the user config.
 */
function getConfiguredFixer(node, context, configs) {
    const text = context.sourceCode.getText(node);
    const config = configs.find((c) => c.pattern.test(text));
    if (config === undefined) {
        return null;
    }
    return (fixer) => fixer.replaceText(node, text.replace(config.pattern, config.replace));
}
/**
 * Get the suggestions that uses the user config.
 */
function getConfiguredSuggestions(node, context, configs) {
    const text = context.sourceCode.getText(node);
    const matchingConfig = configs.filter((c) => c.pattern.test(text));
    if (matchingConfig.length === 0) {
        return null;
    }
    return matchingConfig.map((config) => ({
        fix: (fixer) => fixer.replaceText(node, text.replace(config.pattern, config.replace)),
        messageId: "userDefined",
        data: {
            message: config.message ?? `Replace with: ${text.replace(config.pattern, config.replace)}`,
        },
    }));
}
/**
 * Compare the actual immutability to the expected immutability.
 */
function compareImmutability(rule, actual) {
    switch (rule.comparator) {
        case RuleEnforcementComparator.Less: {
            return actual < rule.immutability;
        }
        case RuleEnforcementComparator.AtMost: {
            return actual <= rule.immutability;
        }
        case RuleEnforcementComparator.Exactly: {
            return actual === rule.immutability;
        }
        case RuleEnforcementComparator.AtLeast: {
            return actual >= rule.immutability;
        }
        case RuleEnforcementComparator.More: {
            return actual > rule.immutability;
        }
    }
}
/**
 * Get the results.
 */
function getResults(node, context, rule, immutability) {
    const valid = compareImmutability(rule, immutability);
    if (valid) {
        return {
            context,
            descriptors: [],
        };
    }
    const messageId = RuleEnforcementComparator[rule.comparator];
    const fix = rule.fixers === false || isTSInterfaceDeclaration(node)
        ? null
        : getConfiguredFixer(node.typeAnnotation, context, rule.fixers);
    const suggest = rule.suggestions === false || isTSInterfaceDeclaration(node)
        ? null
        : getConfiguredSuggestions(node.typeAnnotation, context, rule.suggestions);
    return {
        context,
        descriptors: [
            {
                node: node.id,
                messageId,
                data: {
                    actual: Immutability[immutability],
                    expected: Immutability[rule.immutability],
                },
                fix,
                suggest,
            },
        ],
    };
}
/**
 * Check if the given Interface or Type Alias violates this rule.
 */
function checkTypeDeclaration(node, context, options) {
    const [optionsObject] = options;
    const { ignoreInterfaces, ignoreIdentifierPattern } = optionsObject;
    if (shouldIgnorePattern(node, context, ignoreIdentifierPattern) ||
        (ignoreInterfaces && isTSInterfaceDeclaration(node))) {
        return {
            context,
            descriptors: [],
        };
    }
    const rule = getRuleToApply(node, context, options);
    if (rule === undefined) {
        return {
            context,
            descriptors: [],
        };
    }
    const maxImmutability = rule.comparator === RuleEnforcementComparator.AtLeast
        ? rule.immutability
        : rule.comparator === RuleEnforcementComparator.More
            ? rule.immutability + 1
            : undefined;
    const immutability = getTypeImmutabilityOfNode(node, context, maxImmutability);
    return getResults(node, context, rule, immutability);
}
// Create the rule.
const rule = createRule(name, meta$1, defaultOptions, {
    TSTypeAliasDeclaration: checkTypeDeclaration,
    TSInterfaceDeclaration: checkTypeDeclaration,
});

/**
 * All of the custom rules.
 */
const rules = {
    [name$j]: rule$j,
    [name$i]: rule$i,
    [name$g]: rule$g,
    [name$h]: rule$h,
    [name$f]: rule$f,
    [name$e]: rule$e,
    [name$d]: rule$d,
    [name$c]: rule$c,
    [name$b]: rule$b,
    [name$a]: rule$a,
    [name$9]: rule$9,
    [name$8]: rule$8,
    [name$7]: rule$7,
    [name$6]: rule$6,
    [name$5]: rule$5,
    [name$4]: rule$4,
    [name$3]: rule$3,
    [name$2]: rule$2,
    [name$1]: rule$1,
    [name]: rule,
};

const all = {
    ...Object.fromEntries(Object.entries(rules)
        .filter(([, rule]) => rule.meta.deprecated !== true)
        .map(([name, rule]) => [`${ruleNameScope}/${name}`, rule.meta.docs.recommendedSeverity])),
};

const currying = Object.fromEntries(Object.entries(rules)
    .filter(([, rule]) => rule.meta.deprecated !== true && rule.meta.docs.category === "Currying" && rule.meta.docs.recommended !== false)
    .map(([name, rule]) => [`${ruleNameScope}/${name}`, rule.meta.docs.recommendedSeverity]));

const disableTypeChecked = Object.fromEntries(Object.entries(rules)
    .filter(([, rule]) => rule.meta.docs.requiresTypeChecking)
    .map(([name]) => [`${ruleNameScope}/${name}`, "off"]));

const externalVanillaRecommended = {
    "prefer-const": "error",
    "no-param-reassign": "error",
    "no-var": "error",
};

const tsConfig = {
    "@typescript-eslint/prefer-readonly": "error",
    "@typescript-eslint/switch-exhaustiveness-check": "error",
};
const externalTypeScriptRecommended = {
    ...externalVanillaRecommended,
    ...tsConfig,
};

const recommended = Object.fromEntries(Object.entries(rules)
    .filter(([, rule]) => rule.meta.deprecated !== true &&
    rule.meta.docs.recommended === "recommended" &&
    rule.meta.docs.category !== "Stylistic")
    .map(([name, rule]) => [`${ruleNameScope}/${name}`, rule.meta.docs.recommendedSeverity]));
const overrides$1 = {
    [fullName$a]: [
        "error",
        {
            enforceParameterCount: false,
            overrides: [
                {
                    specifiers: [
                        {
                            from: "file",
                        },
                    ],
                    options: {
                        enforceParameterCount: {
                            count: "atLeastOne",
                            ignoreLambdaExpression: true,
                            ignoreIIFE: true,
                            ignoreGettersAndSetters: true,
                        },
                    },
                },
            ],
        },
    ],
    [fullName$7]: [
        "error",
        {
            allowReturningBranches: true,
        },
    ],
    [fullName$5]: [
        "error",
        {
            allowInForLoopInit: true,
        },
    ],
    [fullName$4]: "off",
    [fullName$3]: [
        "error",
        {
            allowToRejectPromises: true,
        },
    ],
    [fullName$2]: "off",
    [fullName$1]: [
        "error",
        {
            enforcement: "None",
            overrides: [
                {
                    specifiers: [
                        {
                            from: "lib",
                        },
                        {
                            from: "package",
                        },
                    ],
                    options: {
                        ignoreInferredTypes: true,
                        parameters: {
                            enforcement: "ReadonlyShallow",
                        },
                    },
                },
                {
                    specifiers: {
                        from: "file",
                    },
                    options: {
                        ignoreInferredTypes: true,
                        parameters: {
                            enforcement: "ReadonlyDeep",
                        },
                    },
                },
            ],
        },
    ],
    [fullName]: [
        "error",
        {
            rules: [
                {
                    identifiers: ["^I?Immutable.+"],
                    immutability: Immutability.Immutable,
                    comparator: RuleEnforcementComparator.AtLeast,
                },
                {
                    identifiers: ["^I?ReadonlyDeep.+"],
                    immutability: Immutability.ReadonlyDeep,
                    comparator: RuleEnforcementComparator.AtLeast,
                },
                {
                    identifiers: ["^I?Readonly.+"],
                    immutability: Immutability.ReadonlyShallow,
                    comparator: RuleEnforcementComparator.AtLeast,
                    suggestions: [
                        {
                            pattern: "^(Array|Map|Set)<(.+)>$",
                            replace: "Readonly$1<$2>",
                        },
                        {
                            pattern: "^(.+)$",
                            replace: "Readonly<$1>",
                        },
                    ],
                },
                {
                    identifiers: ["^I?Mutable.+"],
                    immutability: Immutability.Mutable,
                    comparator: RuleEnforcementComparator.AtMost,
                    suggestions: [
                        {
                            pattern: "^Readonly(Array|Map|Set)<(.+)>$",
                            replace: "$1<$2>",
                        },
                        {
                            pattern: "^Readonly<(.+)>$",
                            replace: "$1",
                        },
                    ],
                },
            ],
        },
    ],
};
const recommended$1 = {
    ...recommended,
    ...overrides$1,
};

const overrides = {
    [fullName$a]: [
        "error",
        {
            enforceParameterCount: false,
        },
    ],
    [fullName$9]: ["error", { ignoreClasses: "fieldsOnly" }],
    [fullName$8]: "off",
    [fullName$7]: "off",
    [fullName$6]: "off",
    [fullName$1]: [
        "error",
        {
            enforcement: "None",
            overrides: [
                {
                    specifiers: {
                        from: "file",
                    },
                    options: {
                        ignoreInferredTypes: true,
                        parameters: {
                            enforcement: "ReadonlyShallow",
                        },
                    },
                },
            ],
        },
    ],
};
const lite = {
    ...recommended$1,
    ...overrides,
};

const noExceptions = Object.fromEntries(Object.entries(rules)
    .filter(([, rule]) => rule.meta.deprecated !== true &&
    rule.meta.docs.category === "No Exceptions" &&
    rule.meta.docs.recommended !== false)
    .map(([name, rule]) => [`${ruleNameScope}/${name}`, rule.meta.docs.recommendedSeverity]));

const noMutations = Object.fromEntries(Object.entries(rules)
    .filter(([, rule]) => rule.meta.deprecated !== true &&
    rule.meta.docs.category === "No Mutations" &&
    rule.meta.docs.recommended !== false)
    .map(([name, rule]) => [`${ruleNameScope}/${name}`, rule.meta.docs.recommendedSeverity]));

const noOtherParadigms = Object.fromEntries(Object.entries(rules)
    .filter(([, rule]) => rule.meta.deprecated !== true &&
    rule.meta.docs.category === "No Other Paradigms" &&
    rule.meta.docs.recommended !== false)
    .map(([name, rule]) => [`${ruleNameScope}/${name}`, rule.meta.docs.recommendedSeverity]));

const noStatements = Object.fromEntries(Object.entries(rules)
    .filter(([, rule]) => rule.meta.deprecated !== true &&
    rule.meta.docs.category === "No Statements" &&
    rule.meta.docs.recommended !== false)
    .map(([name, rule]) => [`${ruleNameScope}/${name}`, rule.meta.docs.recommendedSeverity]));

const off = Object.fromEntries(Object.entries(rules).map(([name]) => [`${ruleNameScope}/${name}`, "off"]));

const strict = Object.fromEntries(Object.entries(rules)
    .filter(([, rule]) => rule.meta.deprecated !== true &&
    rule.meta.docs.recommended !== false &&
    rule.meta.docs.category !== "Stylistic")
    .map(([name, rule]) => [`${ruleNameScope}/${name}`, rule.meta.docs.recommendedSeverity]));

const stylistic = Object.fromEntries(Object.entries(rules)
    .filter(([, rule]) => rule.meta.deprecated !== true &&
    rule.meta.docs.category === "Stylistic" &&
    rule.meta.docs.recommended !== false)
    .map(([name, rule]) => [`${ruleNameScope}/${name}`, rule.meta.docs.recommendedSeverity]));

const meta = {
    name: "eslint-plugin-functional",
    version: __VERSION__,
};
const functional = {
    meta,
    rules,
};
const plugins = { functional };
const configs = {
    all: { plugins, rules: all },
    lite: { plugins, rules: lite },
    recommended: { plugins, rules: recommended$1 },
    strict: { plugins, rules: strict },
    off: { plugins, rules: off },
    disableTypeChecked: {
        plugins,
        rules: disableTypeChecked,
    },
    externalVanillaRecommended: {
        plugins,
        rules: externalVanillaRecommended,
    },
    externalTypeScriptRecommended: {
        plugins,
        rules: externalTypeScriptRecommended,
    },
    currying: { plugins, rules: currying },
    noExceptions: { plugins, rules: noExceptions },
    noMutations: { plugins, rules: noMutations },
    noOtherParadigms: {
        plugins,
        rules: noOtherParadigms,
    },
    noStatements: { plugins, rules: noStatements },
    stylistic: { plugins, rules: stylistic },
};
// eslint-disable-next-line functional/immutable-data
functional.configs = configs;

export { functional as default };