/* AUTO-GENERATED BY build SCRIPT */
/* eslint-disable perfectionist/sort-imports -- For auto-generate; Do not remove */
import {
  merge,
} from 'object-deep-merge';

import {
  buildForbidRuleDefinition,
} from './buildForbidRuleDefinition.js';
import {
  buildRejectOrPreferRuleDefinition,
} from './buildRejectOrPreferRuleDefinition.js';
import {
  getJsdocProcessorPlugin,
} from './getJsdocProcessorPlugin.js';
import checkAccess from './rules/checkAccess.js';
import checkAlignment from './rules/checkAlignment.js';
import checkExamples from './rules/checkExamples.js';
import checkIndentation from './rules/checkIndentation.js';
import checkLineAlignment from './rules/checkLineAlignment.js';
import checkParamNames from './rules/checkParamNames.js';
import checkPropertyNames from './rules/checkPropertyNames.js';
import checkSyntax from './rules/checkSyntax.js';
import checkTagNames from './rules/checkTagNames.js';
import checkTemplateNames from './rules/checkTemplateNames.js';
import checkTypes from './rules/checkTypes.js';
import checkValues from './rules/checkValues.js';
import convertToJsdocComments from './rules/convertToJsdocComments.js';
import emptyTags from './rules/emptyTags.js';
import escapeInlineTags from './rules/escapeInlineTags.js';
import implementsOnClasses from './rules/implementsOnClasses.js';
import importsAsDependencies from './rules/importsAsDependencies.js';
import informativeDocs from './rules/informativeDocs.js';
import linesBeforeBlock from './rules/linesBeforeBlock.js';
import matchDescription from './rules/matchDescription.js';
import matchName from './rules/matchName.js';
import multilineBlocks from './rules/multilineBlocks.js';
import noBadBlocks from './rules/noBadBlocks.js';
import noBlankBlockDescriptions from './rules/noBlankBlockDescriptions.js';
import noBlankBlocks from './rules/noBlankBlocks.js';
import noDefaults from './rules/noDefaults.js';
import noMissingSyntax from './rules/noMissingSyntax.js';
import noMultiAsterisks from './rules/noMultiAsterisks.js';
import noRestrictedSyntax from './rules/noRestrictedSyntax.js';
import noTypes from './rules/noTypes.js';
import noUndefinedTypes from './rules/noUndefinedTypes.js';
import preferImportTag from './rules/preferImportTag.js';
import requireAsteriskPrefix from './rules/requireAsteriskPrefix.js';
import requireDescription from './rules/requireDescription.js';
import requireDescriptionCompleteSentence from './rules/requireDescriptionCompleteSentence.js';
import requireExample from './rules/requireExample.js';
import requireFileOverview from './rules/requireFileOverview.js';
import requireHyphenBeforeParamDescription from './rules/requireHyphenBeforeParamDescription.js';
import requireJsdoc from './rules/requireJsdoc.js';
import requireParam from './rules/requireParam.js';
import requireParamDescription from './rules/requireParamDescription.js';
import requireParamName from './rules/requireParamName.js';
import requireParamType from './rules/requireParamType.js';
import requireProperty from './rules/requireProperty.js';
import requirePropertyDescription from './rules/requirePropertyDescription.js';
import requirePropertyName from './rules/requirePropertyName.js';
import requirePropertyType from './rules/requirePropertyType.js';
import requireRejects from './rules/requireRejects.js';
import requireReturns from './rules/requireReturns.js';
import requireReturnsCheck from './rules/requireReturnsCheck.js';
import requireReturnsDescription from './rules/requireReturnsDescription.js';
import requireReturnsType from './rules/requireReturnsType.js';
import requireTags from './rules/requireTags.js';
import requireTemplate from './rules/requireTemplate.js';
import requireThrows from './rules/requireThrows.js';
import requireYields from './rules/requireYields.js';
import requireYieldsCheck from './rules/requireYieldsCheck.js';
import sortTags from './rules/sortTags.js';
import tagLines from './rules/tagLines.js';
import textEscaping from './rules/textEscaping.js';
import tsMethodSignatureStyle from './rules/tsMethodSignatureStyle.js';
import tsNoEmptyObjectType from './rules/tsNoEmptyObjectType.js';
import tsNoUnnecessaryTemplateExpression from './rules/tsNoUnnecessaryTemplateExpression.js';
import tsPreferFunctionType from './rules/tsPreferFunctionType.js';
import typeFormatting from './rules/typeFormatting.js';
import validTypes from './rules/validTypes.js';
import {
  ESLint,
} from 'eslint';
import semver from 'semver';

/**
 * @typedef {"recommended" | "stylistic" | "contents" | "logical" | "requirements"} ConfigGroups
 * @typedef {"" | "-typescript" | "-typescript-flavor"} ConfigVariants
 * @typedef {"" | "-error"} ErrorLevelVariants
 * @type {import('eslint').ESLint.Plugin & {
 *   configs: Record<
 *       `flat/${ConfigGroups}${ConfigVariants}${ErrorLevelVariants}`,
 *       import('eslint').Linter.Config
 *     > &
 *     Record<
 *       "examples"|"default-expressions"|"examples-and-default-expressions",
 *       import('eslint').Linter.Config[]
 *     > &
 *     Record<"flat/recommended-mixed", import('eslint').Linter.Config[]>
 * }}
 */
const index = {};
index.configs = {};
index.rules = {
  'check-access': checkAccess,
  'check-alignment': checkAlignment,
  'check-examples': checkExamples,
  'check-indentation': checkIndentation,
  'check-line-alignment': checkLineAlignment,
  'check-param-names': checkParamNames,
  'check-property-names': checkPropertyNames,
  'check-syntax': checkSyntax,
  'check-tag-names': checkTagNames,
  'check-template-names': checkTemplateNames,
  'check-types': checkTypes,
  'check-values': checkValues,
  'convert-to-jsdoc-comments': convertToJsdocComments,
  'empty-tags': emptyTags,
  'escape-inline-tags': escapeInlineTags,
  'implements-on-classes': implementsOnClasses,
  'imports-as-dependencies': importsAsDependencies,
  'informative-docs': informativeDocs,
  'lines-before-block': linesBeforeBlock,
  'match-description': matchDescription,
  'match-name': matchName,
  'multiline-blocks': multilineBlocks,
  'no-bad-blocks': noBadBlocks,
  'no-blank-block-descriptions': noBlankBlockDescriptions,
  'no-blank-blocks': noBlankBlocks,
  'no-defaults': noDefaults,
  'no-missing-syntax': noMissingSyntax,
  'no-multi-asterisks': noMultiAsterisks,
  'no-restricted-syntax': noRestrictedSyntax,
  'no-types': noTypes,
  'no-undefined-types': noUndefinedTypes,
  'prefer-import-tag': preferImportTag,
  'reject-any-type': buildRejectOrPreferRuleDefinition({
    description: 'Reports use of `any` or `*` type',
    overrideSettings: {
      '*': {
        message: 'Prefer a more specific type to `*`',
        replacement: false,
        unifyParentAndChildTypeChecks: true,
      },
      any: {
        message: 'Prefer a more specific type to `any`',
        replacement: false,
        unifyParentAndChildTypeChecks: true,
      },
    },
    url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/reject-any-type.md#repos-sticky-header',
  }),
  'reject-function-type': buildRejectOrPreferRuleDefinition({
    description: 'Reports use of `Function` type',
    overrideSettings: {
      Function: {
        message: 'Prefer a more specific type to `Function`',
        replacement: false,
        unifyParentAndChildTypeChecks: true,
      },
    },
    url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/reject-function-type.md#repos-sticky-header',
  }),
  'require-asterisk-prefix': requireAsteriskPrefix,
  'require-description': requireDescription,
  'require-description-complete-sentence': requireDescriptionCompleteSentence,
  'require-example': requireExample,
  'require-file-overview': requireFileOverview,
  'require-hyphen-before-param-description': requireHyphenBeforeParamDescription,
  'require-jsdoc': requireJsdoc,
  'require-next-description': buildForbidRuleDefinition({
    contexts: [
      {
        comment: 'JsdocBlock:has(JsdocTag[tag=next]:not([name!=""]):not([description!=""]))',
        context: 'any',
        message: '@next should have a description',
      },
    ],
    description: 'Requires a description for `@next` tags',
    url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-next-description.md#repos-sticky-header',
  }),
  'require-next-type': buildForbidRuleDefinition({
    contexts: [
      {
        comment: 'JsdocBlock:has(JsdocTag[tag=next]:not([parsedType.type]))',
        context: 'any',
        message: '@next should have a type',
      },
    ],
    description: 'Requires a type for `@next` tags',
    url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-next-type.md#repos-sticky-header',
  }),
  'require-param': requireParam,
  'require-param-description': requireParamDescription,
  'require-param-name': requireParamName,
  'require-param-type': requireParamType,
  'require-property': requireProperty,
  'require-property-description': requirePropertyDescription,
  'require-property-name': requirePropertyName,
  'require-property-type': requirePropertyType,
  'require-rejects': requireRejects,
  'require-returns': requireReturns,
  'require-returns-check': requireReturnsCheck,
  'require-returns-description': requireReturnsDescription,
  'require-returns-type': requireReturnsType,
  'require-tags': requireTags,
  'require-template': requireTemplate,
  'require-template-description': buildForbidRuleDefinition({
    contexts: [
      {
        comment: 'JsdocBlock:has(JsdocTag[tag=template]:not([description!=""]))',
        context: 'any',
        message: '@template should have a description',
      },
    ],
    description: 'Requires a description for `@template` tags',
    url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-template-description.md#repos-sticky-header',
  }),
  'require-throws': requireThrows,
  'require-throws-description': buildForbidRuleDefinition({
    contexts: [
      {
        comment: 'JsdocBlock:has(JsdocTag[tag=/^(?:throws|exception)$/]:not([description!=""]))',
        context: 'any',
        message: '@throws should have a description',
      },
    ],
    description: 'Requires a description for `@throws` tags',
    url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-throws-description.md#repos-sticky-header',
  }),
  'require-throws-type': buildForbidRuleDefinition({
    contexts: [
      {
        comment: 'JsdocBlock:has(JsdocTag[tag=/^(?:throws|exception)$/]:not([parsedType.type]))',
        context: 'any',
        message: '@throws should have a type',
      },
    ],
    description: 'Requires a type for `@throws` tags',
    url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-throws-type.md#repos-sticky-header',
  }),
  'require-yields': requireYields,
  'require-yields-check': requireYieldsCheck,
  'require-yields-description': buildForbidRuleDefinition({
    contexts: [
      {
        comment: 'JsdocBlock:has(JsdocTag[tag=/^yields?$/]:not([name!=""]):not([description!=""]))',
        context: 'any',
        message: '@yields should have a description',
      },
    ],
    description: 'Requires a description for `@yields` tags',
    url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-yields-description.md#repos-sticky-header',
  }),
  'require-yields-type': buildForbidRuleDefinition({
    contexts: [
      {
        comment: 'JsdocBlock:has(JsdocTag[tag=/^yields?$/]:not([parsedType.type]))',
        context: 'any',
        message: '@yields should have a type',
      },
    ],
    description: 'Requires a type for `@yields` tags',
    url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-yields-type.md#repos-sticky-header',
  }),
  'sort-tags': sortTags,
  'tag-lines': tagLines,
  'text-escaping': textEscaping,
  'ts-method-signature-style': tsMethodSignatureStyle,
  'ts-no-empty-object-type': tsNoEmptyObjectType,
  'ts-no-unnecessary-template-expression': tsNoUnnecessaryTemplateExpression,
  'ts-prefer-function-type': tsPreferFunctionType,
  'type-formatting': typeFormatting,
  'valid-types': validTypes,
};

/**
 * @param {"warn"|"error"} warnOrError
 * @param {string} [flatName]
 * @returns {import('eslint').Linter.Config}
 */
const createRecommendedRuleset = (warnOrError, flatName) => {
  return {
    ...(flatName ? {
      name: 'jsdoc/' + flatName,
    } : {}),
    // @ts-expect-error ESLint 8 plugins
    plugins:
      flatName ? {
        jsdoc: index,
      } : [
        'jsdoc',
      ],
    rules: {
      'jsdoc/check-access': warnOrError,
      'jsdoc/check-alignment': warnOrError,
      'jsdoc/check-examples': 'off',
      'jsdoc/check-indentation': 'off',
      'jsdoc/check-line-alignment': 'off',
      'jsdoc/check-param-names': warnOrError,
      'jsdoc/check-property-names': warnOrError,
      'jsdoc/check-syntax': 'off',
      'jsdoc/check-tag-names': warnOrError,
      'jsdoc/check-template-names': 'off',
      'jsdoc/check-types': warnOrError,
      'jsdoc/check-values': warnOrError,
      'jsdoc/convert-to-jsdoc-comments': 'off',
      'jsdoc/empty-tags': warnOrError,
      'jsdoc/escape-inline-tags': warnOrError,
      'jsdoc/implements-on-classes': warnOrError,
      'jsdoc/imports-as-dependencies': 'off',
      'jsdoc/informative-docs': 'off',
      'jsdoc/lines-before-block': 'off',
      'jsdoc/match-description': 'off',
      'jsdoc/match-name': 'off',
      'jsdoc/multiline-blocks': warnOrError,
      'jsdoc/no-bad-blocks': 'off',
      'jsdoc/no-blank-block-descriptions': 'off',
      'jsdoc/no-blank-blocks': 'off',
      'jsdoc/no-defaults': warnOrError,
      'jsdoc/no-missing-syntax': 'off',
      'jsdoc/no-multi-asterisks': warnOrError,
      'jsdoc/no-restricted-syntax': 'off',
      'jsdoc/no-types': 'off',
      'jsdoc/no-undefined-types': warnOrError,
      'jsdoc/prefer-import-tag': 'off',
      'jsdoc/reject-any-type': warnOrError,
      'jsdoc/reject-function-type': warnOrError,
      'jsdoc/require-asterisk-prefix': 'off',
      'jsdoc/require-description': 'off',
      'jsdoc/require-description-complete-sentence': 'off',
      'jsdoc/require-example': 'off',
      'jsdoc/require-file-overview': 'off',
      'jsdoc/require-hyphen-before-param-description': 'off',
      'jsdoc/require-jsdoc': warnOrError,
      'jsdoc/require-next-description': 'off',
      'jsdoc/require-next-type': warnOrError,
      'jsdoc/require-param': warnOrError,
      'jsdoc/require-param-description': warnOrError,
      'jsdoc/require-param-name': warnOrError,
      'jsdoc/require-param-type': warnOrError,
      'jsdoc/require-property': warnOrError,
      'jsdoc/require-property-description': warnOrError,
      'jsdoc/require-property-name': warnOrError,
      'jsdoc/require-property-type': warnOrError,
      'jsdoc/require-rejects': 'off',
      'jsdoc/require-returns': warnOrError,
      'jsdoc/require-returns-check': warnOrError,
      'jsdoc/require-returns-description': warnOrError,
      'jsdoc/require-returns-type': warnOrError,
      'jsdoc/require-tags': 'off',
      'jsdoc/require-template': 'off',
      'jsdoc/require-template-description': 'off',
      'jsdoc/require-throws': 'off',
      'jsdoc/require-throws-description': 'off',
      'jsdoc/require-throws-type': warnOrError,
      'jsdoc/require-yields': warnOrError,
      'jsdoc/require-yields-check': warnOrError,
      'jsdoc/require-yields-description': 'off',
      'jsdoc/require-yields-type': warnOrError,
      'jsdoc/sort-tags': 'off',
      'jsdoc/tag-lines': warnOrError,
      'jsdoc/text-escaping': 'off',
      'jsdoc/ts-method-signature-style': 'off',
      'jsdoc/ts-no-empty-object-type': warnOrError,
      'jsdoc/ts-no-unnecessary-template-expression': 'off',
      'jsdoc/ts-prefer-function-type': 'off',
      'jsdoc/type-formatting': 'off',
      'jsdoc/valid-types': warnOrError,
    },
  };
};

/**
 * @param {"warn"|"error"} warnOrError
 * @param {string} [flatName]
 * @returns {import('eslint').Linter.Config}
 */
const createRecommendedTypeScriptRuleset = (warnOrError, flatName) => {
  const ruleset = createRecommendedRuleset(warnOrError, flatName);

  return {
    ...ruleset,
    rules: {
      ...ruleset.rules,
      /* eslint-disable @stylistic/indent -- Extra indent to avoid use by auto-rule-editing */
        'jsdoc/check-tag-names': [
          warnOrError, {
            typed: true,
          },
        ],
        'jsdoc/no-types': warnOrError,
        'jsdoc/no-undefined-types': 'off',
        'jsdoc/require-param-type': 'off',
        'jsdoc/require-property-type': 'off',
        'jsdoc/require-returns-type': 'off',
      /* eslint-enable @stylistic/indent */
    },
  };
};

/**
 * @param {"warn"|"error"} warnOrError
 * @param {string} [flatName]
 * @returns {import('eslint').Linter.Config}
 */
const createRecommendedTsDocRuleset = (warnOrError, flatName) => {
  const ruleset = createRecommendedTypeScriptRuleset(warnOrError, flatName);

  return {
    ...ruleset,
    rules: {
      ...ruleset.rules,
      /* eslint-disable @stylistic/indent -- Extra indent to avoid use by auto-rule-editing */
        'jsdoc/require-next-type': 'off',
        'jsdoc/require-throws-type': 'off',
        'jsdoc/require-yields-type': 'off',
      /* eslint-enable @stylistic/indent */
    },
  };
};

/**
 * @param {"warn"|"error"} warnOrError
 * @param {string} [flatName]
 * @returns {import('eslint').Linter.Config}
 */
const createRecommendedTypeScriptFlavorRuleset = (warnOrError, flatName) => {
  const ruleset = createRecommendedRuleset(warnOrError, flatName);

  return {
    ...ruleset,
    rules: {
      ...ruleset.rules,
      /* eslint-disable @stylistic/indent -- Extra indent to avoid use by auto-rule-editing */
        'jsdoc/no-undefined-types': 'off',
      /* eslint-enable @stylistic/indent */
    },
  };
};

/**
 * @param {(string | unknown[])[]} ruleNames
 */
const createStandaloneRulesetFactory = (ruleNames) => {
  /**
   * @param {"warn"|"error"} warnOrError
   * @param {string} [flatName]
   * @returns {import('eslint').Linter.Config}
   */
  return (warnOrError, flatName) => {
    return {
      name: 'jsdoc/' + flatName,
      plugins: {
        jsdoc: index,
      },
      rules: Object.fromEntries(
        ruleNames.map(
          (ruleName) => {
            return (typeof ruleName === 'string' ?
              [
                ruleName, warnOrError,
              ] :
              [
                ruleName[0], [
                  warnOrError, ...ruleName.slice(1),
                ],
              ]);
          },
        ),
      ),
    };
  };
};

const contentsRules = [
  'jsdoc/informative-docs',
  'jsdoc/match-description',
  'jsdoc/no-blank-block-descriptions',
  'jsdoc/no-blank-blocks',
  [
    'jsdoc/text-escaping', {
      escapeHTML: true,
    },
  ],
];

const createContentsTypescriptRuleset = createStandaloneRulesetFactory(contentsRules);

const createContentsTypescriptFlavorRuleset = createStandaloneRulesetFactory(contentsRules);

const logicalRules = [
  'jsdoc/check-access',
  'jsdoc/check-param-names',
  'jsdoc/check-property-names',
  'jsdoc/check-syntax',
  'jsdoc/check-tag-names',
  'jsdoc/check-template-names',
  'jsdoc/check-types',
  'jsdoc/check-values',
  'jsdoc/empty-tags',
  'jsdoc/escape-inline-tags',
  'jsdoc/implements-on-classes',
  'jsdoc/require-returns-check',
  'jsdoc/require-yields-check',
  'jsdoc/no-bad-blocks',
  'jsdoc/no-defaults',
  'jsdoc/no-types',
  'jsdoc/no-undefined-types',
  'jsdoc/valid-types',
];

const createLogicalTypescriptRuleset = createStandaloneRulesetFactory(logicalRules);

const createLogicalTypescriptFlavorRuleset = createStandaloneRulesetFactory(logicalRules);

const requirementsRules = [
  'jsdoc/require-example',
  'jsdoc/require-jsdoc',
  'jsdoc/require-next-type',
  'jsdoc/require-param',
  'jsdoc/require-param-description',
  'jsdoc/require-param-name',
  'jsdoc/require-property',
  'jsdoc/require-property-description',
  'jsdoc/require-property-name',
  'jsdoc/require-returns',
  'jsdoc/require-returns-description',
  'jsdoc/require-throws-type',
  'jsdoc/require-yields',
  'jsdoc/require-yields-type',
];

const createRequirementsTypeScriptRuleset = createStandaloneRulesetFactory(requirementsRules);

const createRequirementsTypeScriptFlavorRuleset = createStandaloneRulesetFactory([
  ...requirementsRules,
  'jsdoc/require-param-type',
  'jsdoc/require-property-type',
  'jsdoc/require-returns-type',
  'jsdoc/require-template',
]);

const stylisticRules = [
  'jsdoc/check-alignment',
  'jsdoc/check-line-alignment',
  'jsdoc/lines-before-block',
  'jsdoc/multiline-blocks',
  'jsdoc/no-multi-asterisks',
  'jsdoc/require-asterisk-prefix',
  [
    'jsdoc/require-hyphen-before-param-description', 'never',
  ],
  'jsdoc/tag-lines',
];

const createStylisticTypeScriptRuleset = createStandaloneRulesetFactory(stylisticRules);

const createStylisticTypeScriptFlavorRuleset = createStandaloneRulesetFactory(stylisticRules);

/* c8 ignore next 3 -- TS */
if (!index.configs) {
  throw new Error('TypeScript guard');
}

index.configs.recommended = createRecommendedRuleset('warn');
index.configs['recommended-error'] = createRecommendedRuleset('error');
index.configs['recommended-typescript'] = createRecommendedTypeScriptRuleset('warn');
index.configs['recommended-typescript-error'] = createRecommendedTypeScriptRuleset('error');
index.configs['recommended-typescript-flavor'] = createRecommendedTypeScriptFlavorRuleset('warn');
index.configs['recommended-typescript-flavor-error'] = createRecommendedTypeScriptFlavorRuleset('error');
index.configs['recommended-tsdoc'] = createRecommendedTsDocRuleset('warn');
index.configs['recommended-tsdoc-error'] = createRecommendedTsDocRuleset('error');

index.configs['flat/recommended'] = createRecommendedRuleset('warn', 'flat/recommended');
index.configs['flat/recommended-error'] = createRecommendedRuleset('error', 'flat/recommended-error');
index.configs['flat/recommended-typescript'] = createRecommendedTypeScriptRuleset('warn', 'flat/recommended-typescript');
index.configs['flat/recommended-typescript-error'] = createRecommendedTypeScriptRuleset('error', 'flat/recommended-typescript-error');
index.configs['flat/recommended-typescript-flavor'] = createRecommendedTypeScriptFlavorRuleset('warn', 'flat/recommended-typescript-flavor');
index.configs['flat/recommended-typescript-flavor-error'] = createRecommendedTypeScriptFlavorRuleset('error', 'flat/recommended-typescript-flavor-error');
index.configs['flat/recommended-tsdoc'] = createRecommendedTsDocRuleset('warn', 'flat/recommended-tsdoc');
index.configs['flat/recommended-tsdoc-error'] = createRecommendedTsDocRuleset('error', 'flat/recommended-tsdoc-error');

index.configs['flat/contents-typescript'] = createContentsTypescriptRuleset('warn', 'flat/contents-typescript');
index.configs['flat/contents-typescript-error'] = createContentsTypescriptRuleset('error', 'flat/contents-typescript-error');
index.configs['flat/contents-typescript-flavor'] = createContentsTypescriptFlavorRuleset('warn', 'flat/contents-typescript-flavor');
index.configs['flat/contents-typescript-flavor-error'] = createContentsTypescriptFlavorRuleset('error', 'flat/contents-typescript-error-flavor');
index.configs['flat/logical-typescript'] = createLogicalTypescriptRuleset('warn', 'flat/logical-typescript');
index.configs['flat/logical-typescript-error'] = createLogicalTypescriptRuleset('error', 'flat/logical-typescript-error');
index.configs['flat/logical-typescript-flavor'] = createLogicalTypescriptFlavorRuleset('warn', 'flat/logical-typescript-flavor');
index.configs['flat/logical-typescript-flavor-error'] = createLogicalTypescriptFlavorRuleset('error', 'flat/logical-typescript-error-flavor');
index.configs['flat/requirements-typescript'] = createRequirementsTypeScriptRuleset('warn', 'flat/requirements-typescript');
index.configs['flat/requirements-typescript-error'] = createRequirementsTypeScriptRuleset('error', 'flat/requirements-typescript-error');
index.configs['flat/requirements-typescript-flavor'] = createRequirementsTypeScriptFlavorRuleset('warn', 'flat/requirements-typescript-flavor');
index.configs['flat/requirements-typescript-flavor-error'] = createRequirementsTypeScriptFlavorRuleset('error', 'flat/requirements-typescript-error-flavor');
index.configs['flat/stylistic-typescript'] = createStylisticTypeScriptRuleset('warn', 'flat/stylistic-typescript');
index.configs['flat/stylistic-typescript-error'] = createStylisticTypeScriptRuleset('error', 'flat/stylistic-typescript-error');
index.configs['flat/stylistic-typescript-flavor'] = createStylisticTypeScriptFlavorRuleset('warn', 'flat/stylistic-typescript-flavor');
index.configs['flat/stylistic-typescript-flavor-error'] = createStylisticTypeScriptFlavorRuleset('error', 'flat/stylistic-typescript-error-flavor');

index.configs.examples = /** @type {import('eslint').Linter.Config[]} */ ([
  {
    files: [
      '**/*.js',
    ],
    name: 'jsdoc/examples/processor',
    plugins: {
      examples: getJsdocProcessorPlugin(),
    },
    processor: 'examples/examples',
  },
  {
    files: [
      '**/*.md/*.js',
    ],
    name: 'jsdoc/examples/rules',
    rules: {
      // "always" newline rule at end unlikely in sample code
      '@stylistic/eol-last': 0,
      // Often wish to start `@example` code after newline; also may use
      //   empty lines for spacing
      '@stylistic/no-multiple-empty-lines': 0,

      // Can generally look nicer to pad a little even if code imposes more stringency
      '@stylistic/padded-blocks': 0,

      '@typescript-eslint/no-unused-vars': 0,

      // Wouldn't generally expect example paths to resolve relative to JS file
      'import/no-unresolved': 0,

      // Snippets likely too short to always include import/export info
      'import/unambiguous': 0,

      'jsdoc/require-file-overview': 0,

      // The end of a multiline comment would end the comment the example is in.
      'jsdoc/require-jsdoc': 0,

      // See import/no-unresolved
      'n/no-missing-import': 0,

      'n/no-missing-require': 0,

      // Unlikely to have inadvertent debugging within examples
      'no-console': 0,

      /* c8 ignore next 11 -- Coercion should work */
      ...(semver.gte(semver.coerce(ESLint.version) ?? '9.0.0', '9.0.0') ? {} : {
        // "always" newline rule at end unlikely in sample code
        'eol-last': 0,

        // Often wish to start `@example` code after newline; also may use
        //   empty lines for spacing
        'no-multiple-empty-lines': 0,

        // Can generally look nicer to pad a little even if code imposes more stringency
        'padded-blocks': 0,
      }),

      // Many variables in examples will be `undefined`
      'no-undef': 0,
      // Common to define variables for clarity without always using them
      'no-unused-vars': 0,

      // See import/no-unresolved
      'node/no-missing-import': 0,
      'node/no-missing-require': 0,
    },
  },
]);

index.configs['default-expressions'] = /** @type {import('eslint').Linter.Config[]} */ ([
  {
    files: [
      '**/*.js',
    ],
    name: 'jsdoc/default-expressions/processor',
    plugins: {
      examples: getJsdocProcessorPlugin({
        checkDefaults: true,
        checkParams: true,
        checkProperties: true,
      }),
    },
    processor: 'examples/examples',
  },
  {
    files: [
      '**/*.jsdoc-defaults', '**/*.jsdoc-params', '**/*.jsdoc-properties',
    ],
    name: 'jsdoc/default-expressions/rules',
    rules: {
      ...index.configs.examples[1].rules,
      '@stylistic/quotes': [
        'error', 'double',
      ],
      '@stylistic/semi': [
        'error', 'never',
      ],
      '@typescript-eslint/no-unused-expressions': 0,
      'chai-friendly/no-unused-expressions': 0,
      'no-empty-function': 0,
      'no-new': 0,
      'no-unused-expressions': 0,
      /* c8 ignore next 8 -- Coercion should work */
      ...(semver.gte(semver.coerce(ESLint.version) ?? '9.0.0', '9.0.0') ? {} : {
        quotes: [
          'error', 'double',
        ],
        semi: [
          'error', 'never',
        ],
      }),
      strict: 0,
    },
  },
]);

index.configs['examples-and-default-expressions'] = /** @type {import('eslint').Linter.Config[]} */ ([
  {
    name: 'jsdoc/examples-and-default-expressions',
    plugins: {
      examples: getJsdocProcessorPlugin({
        checkDefaults: true,
        checkParams: true,
        checkProperties: true,
      }),
    },
  },
  ...index.configs.examples.map((config) => {
    return {
      ...config,
      plugins: {},
    };
  }),
  ...index.configs['default-expressions'].map((config) => {
    return {
      ...config,
      plugins: {},
    };
  }),
]);

index.configs['flat/recommended-mixed'] = [
  {
    ...index.configs['flat/recommended-typescript-flavor'],
    files: [
      '**/*.{js,jsx,cjs,mjs}',
    ],
  },
  {
    ...index.configs['flat/recommended-typescript'],
    files: [
      '**/*.{ts,tsx,cts,mts}',
    ],
  },
];

export default index;

/**
 * @type {((
 *   cfg?: import('eslint').Linter.Config & {
 *     config?: `flat/${ConfigGroups}${ConfigVariants}${ErrorLevelVariants}`,
 *     mergeSettings?: boolean,
 *     settings?: Partial<import('./iterateJsdoc.js').Settings>,
 *     rules?: {[key in keyof import('./rules.d.ts').Rules]?: import('eslint').Linter.RuleEntry<import('./rules.d.ts').Rules[key]>},
 *     extraRuleDefinitions?: {
 *       forbid?: {
 *         [contextName: string]: {
 *           description?: string,
 *           url?: string,
 *           contexts: (string|{
 *             message: string,
 *             context: string,
 *             comment: string
 *           })[]
 *         }
 *       },
 *       preferTypes?: {
 *         [typeName: string]: {
 *           description: string,
 *           overrideSettings: {
 *             [typeNodeName: string]: {
 *               message: string,
 *               replacement?: false|string,
 *               unifyParentAndChildTypeChecks?: boolean,
 *             }
 *           },
 *           url: string,
 *         }
 *       }
 *     }
 *   }
 * ) => import('eslint').Linter.Config)}
 */
export const jsdoc = function (cfg) {
  /** @type {import('eslint').Linter.Config} */
  let outputConfig = {
    plugins: {
      jsdoc: index,
    },
  };

  if (cfg) {
    if (cfg.config) {
      // @ts-expect-error Security check
      if (cfg.config === '__proto__') {
        throw new TypeError('Disallowed config value');
      }

      outputConfig = /** @type {import('eslint').Linter.Config} */ (index.configs[cfg.config]);
    }

    if (cfg.rules) {
      outputConfig.rules = {
        ...outputConfig.rules,
        ...cfg.rules,
      };
    }

    if (cfg.plugins) {
      outputConfig.plugins = {
        ...outputConfig.plugins,
        ...cfg.plugins,
      };
    }

    if (cfg.name) {
      outputConfig.name = cfg.name;
    }

    if (cfg.basePath) {
      outputConfig.basePath = cfg.basePath;
    }

    if (cfg.files) {
      outputConfig.files = cfg.files;
    }

    if (cfg.ignores) {
      outputConfig.ignores = cfg.ignores;
    }

    if (cfg.language) {
      outputConfig.language = cfg.language;
    }

    if (cfg.languageOptions) {
      outputConfig.languageOptions = cfg.languageOptions;
    }

    if (cfg.linterOptions) {
      outputConfig.linterOptions = cfg.linterOptions;
    }

    if (cfg.processor) {
      outputConfig.processor = cfg.processor;
    }

    if (cfg.extraRuleDefinitions) {
      if (!outputConfig.plugins?.jsdoc?.rules) {
        throw new Error('JSDoc plugin required for `extraRuleDefinitions`');
      }

      if (cfg.extraRuleDefinitions.forbid) {
        for (const [
          contextName,
          {
            contexts,
            description,
            url,
          },
        ] of Object.entries(cfg.extraRuleDefinitions.forbid)) {
          outputConfig.plugins.jsdoc.rules[`forbid-${contextName}`] =
            buildForbidRuleDefinition({
              contextName,
              contexts,
              description,
              url,
            });
        }
      }

      if (cfg.extraRuleDefinitions.preferTypes) {
        for (const [
          typeName,
          {
            description,
            overrideSettings,
            url,
          },
        ] of Object.entries(cfg.extraRuleDefinitions.preferTypes)) {
          outputConfig.plugins.jsdoc.rules[`prefer-type-${typeName}`] =
            buildRejectOrPreferRuleDefinition({
              description,
              overrideSettings,
              typeName,
              url,
            });
        }
      }
    }
  }

  outputConfig.settings = {
    jsdoc: cfg?.mergeSettings === false ?
      cfg.settings :
      merge(
        {},
        cfg?.settings ?? {},
        cfg?.config?.includes('recommended') ?
          {
            // We may need to drop these for "typescript" (non-"flavor") configs,
            //   if support is later added: https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html
            structuredTags: {
              next: {
                required: [
                  'type',
                ],
              },
              rejects: {
                required: [
                  'type',
                ],
              },
            },
          } :
          {},
      ),
  };

  return outputConfig;
};

export {
  getJsdocProcessorPlugin,
} from './getJsdocProcessorPlugin.js';
