import { Linter, Rule, ESLint } from 'eslint';

/**
 * Alias to `Linter.Config`
 *
 * @deprecated
 */
interface FlatConfigItem extends Linter.Config {
}
/**
 * A type that can be awaited. Promise<T> or T.
 */
type Awaitable<T> = T | Promise<T>;
/**
 * A type that can be an array or a single item.
 */
type Arrayable<T> = T | T[];
/**
 * Default config names map. Used for type augmentation.
 *
 * @example
 * ```ts
 * declare module 'eslint-flat-config-utils' {
 *   interface DefaultConfigNamesMap {
 *     'my-custom-config': true
 *   }
 * }
 * ```
 */
interface DefaultConfigNamesMap {
}
interface Nothing {
}
/**
 * type StringLiteralUnion<'foo'> = 'foo' | string
 * This has auto completion whereas `'foo' | string` doesn't
 * Adapted from https://github.com/microsoft/TypeScript/issues/29729
 */
type StringLiteralUnion<T extends U, U = string> = T | (U & Nothing);
type FilterType<T, F> = T extends F ? T : never;
type NullableObject<T> = {
    [K in keyof T]?: T[K] | null | undefined;
};
type GetRuleRecordFromConfig<T> = T extends {
    rules?: infer R;
} ? R : Linter.RulesRecord;

declare const DEFAULT_PLUGIN_CONFLICTS_ERROR = "Different instances of plugin \"{{pluginName}}\" found in multiple configs: {{configNames}}. It's likely you misconfigured the merge of these configs.";
interface DisableFixesOptions {
    builtinRules?: Map<string, Rule.RuleModule> | (() => Awaitable<Map<string, Rule.RuleModule>>);
}
type PluginConflictsError<T extends Linter.Config = Linter.Config> = (pluginName: string, configs: T[]) => string;
/**
 * Awaitable array of ESLint flat configs or a composer object.
 */
type ResolvableFlatConfig<T extends Linter.Config = Linter.Config> = Awaitable<Arrayable<(T | false | undefined | null)>> | Awaitable<(Linter.Config | false | undefined | null)[]> | FlatConfigComposer<any>;
/**
 * Create a chainable composer object that makes manipulating ESLint flat config easier.
 *
 * It extends Promise, so that you can directly await or export it to `eslint.config.mjs`
 *
 * ```ts
 * // eslint.config.mjs
 * import { composer } from 'eslint-flat-config-utils'
 *
 * export default composer(
 *   {
 *     plugins: {},
 *     rules: {},
 *   }
 *   // ...some configs, accepts same arguments as `concat`
 * )
 *   .append(
 *     // appends more configs at the end, accepts same arguments as `concat`
 *   )
 *   .prepend(
 *     // prepends more configs at the beginning, accepts same arguments as `concat`
 *   )
 *   .insertAfter(
 *     'config-name', // specify the name of the target config, or index
 *     // insert more configs after the target, accepts same arguments as `concat`
 *   )
 *   .renamePlugins({
 *     // rename plugins
 *     'old-name': 'new-name',
 *     // for example, rename `n` from `eslint-plugin-n` to more a explicit prefix `node`
 *     'n': 'node'
 *     // applies to all plugins and rules in the configs
 *   })
 *   .override(
 *     'config-name', // specify the name of the target config, or index
 *     {
 *       // merge with the target config
 *       rules: {
 *         'no-console': 'off'
 *       },
 *     }
 *   )
 *
 * // And you an directly return the composer object to `eslint.config.mjs`
 * ```
 */
declare function composer<T extends Linter.Config = Linter.Config, ConfigNames extends string = keyof DefaultConfigNamesMap>(...configs: ResolvableFlatConfig<Linter.Config extends T ? T : Linter.Config>[]): FlatConfigComposer<Linter.Config extends T ? T : Linter.Config, ConfigNames>;
/**
 * The underlying impolementation of `composer()`.
 */
declare class FlatConfigComposer<T extends object = Linter.Config, ConfigNames extends string = keyof DefaultConfigNamesMap> extends Promise<T[]> {
    private _operations;
    private _operationsOverrides;
    private _operationsResolved;
    private _renames;
    private _pluginsConflictsError;
    constructor(...configs: ResolvableFlatConfig<T>[]);
    /**
     * Set plugin renames, like `n` -> `node`, `import-x` -> `import`, etc.
     *
     * This will runs after all config items are resolved. Applies to `plugins` and `rules`.
     */
    renamePlugins(renames: Record<string, string>): this;
    /**
     * Append configs to the end of the current configs array.
     */
    append(...items: ResolvableFlatConfig<T>[]): this;
    /**
     * Prepend configs to the beginning of the current configs array.
     */
    prepend(...items: ResolvableFlatConfig<T>[]): this;
    /**
     * Insert configs before a specific config.
     */
    insertBefore(nameOrIndex: StringLiteralUnion<ConfigNames, string | number>, ...items: ResolvableFlatConfig<T>[]): this;
    /**
     * Insert configs after a specific config.
     */
    insertAfter(nameOrIndex: StringLiteralUnion<ConfigNames, string | number>, ...items: ResolvableFlatConfig<T>[]): this;
    /**
     * Provide overrides to a specific config.
     *
     * It will be merged with the original config, or provide a custom function to replace the config entirely.
     */
    override(nameOrIndex: StringLiteralUnion<ConfigNames, string | number>, config: T | ((config: T) => Awaitable<T>)): this;
    /**
     * Provide overrides to multiple configs as an object map.
     *
     * Same as calling `override` multiple times.
     */
    overrides(overrides: Partial<Record<StringLiteralUnion<ConfigNames, string | number>, T | ((config: T) => Awaitable<T>)>>): this;
    /**
     * Override rules and it's options in **all configs**.
     *
     * Pass `null` as the value to remove the rule.
     *
     * @example
     * ```ts
     * composer
     *   .overrideRules({
     *      'no-console': 'off',
     *      'no-unused-vars': ['error', { vars: 'all', args: 'after-used' }],
     *      // remove the rule from all configs
     *      'no-undef': null,
     *   })
     * ```
     */
    overrideRules(rules: NullableObject<GetRuleRecordFromConfig<T>>): this;
    /**
     * Remove rules from **all configs**.
     *
     * @example
     * ```ts
     * composer
     *  .removeRules(
     *    'no-console',
     *    'no-unused-vars'
     *  )
     * ```
     */
    removeRules(...rules: StringLiteralUnion<FilterType<keyof GetRuleRecordFromConfig<T>, string>, string>[]): this;
    /**
     * Remove plugins by name and all the rules referenced by them.
     *
     * @example
     * ```ts
     * composer
     *   .removePlugins(
     *     'node'
     *   )
     * ```
     *
     * The `plugins: { node }` and `rules: { 'node/xxx': 'error' }` will be removed from all configs.
     */
    removePlugins(...names: string[]): this;
    /**
     * Remove a specific config by name or index.
     */
    remove(nameOrIndex: ConfigNames | string | number): this;
    /**
     * Replace a specific config by name or index.
     *
     * The original config will be removed and replaced with the new one.
     */
    replace(nameOrIndex: StringLiteralUnion<ConfigNames, string | number>, ...items: ResolvableFlatConfig<T>[]): this;
    /**
     * Hijack into plugins to disable fixes for specific rules.
     *
     * Note this mutates the plugin object, use with caution.
     *
     * @example
     * ```ts
     * const config = await composer(...)
     *  .disableRulesFix([
     *    'unused-imports/no-unused-imports',
     *    'vitest/no-only-tests'
     *  ])
     * ```
     */
    disableRulesFix(ruleIds: string[], options?: DisableFixesOptions): this;
    /**
     * Set a custom warning message for plugins conflicts.
     *
     * The error message can be a string or a function that returns a string.
     *
     * Error message accepts template strings:
     * - `{{pluginName}}`: the name of the plugin that has conflicts
     * - `{{configName1}}`: the name of the first config that uses the plugin
     * - `{{configName2}}`: the name of the second config that uses the plugin
     * - `{{configNames}}`: a list of config names that uses the plugin
     *
     * When only one argument is provided, it will be used as the default error message.
     */
    setPluginConflictsError(warning?: string | PluginConflictsError): this;
    setPluginConflictsError(pluginName: string, warning: string | PluginConflictsError): this;
    private _verifyPluginsConflicts;
    /**
     * Hook when all configs are resolved but before returning the final configs.
     *
     * You can modify the final configs here.
     */
    onResolved(callback: (configs: T[]) => Awaitable<T[] | void>): this;
    /**
     * Clone the composer object.
     */
    clone(): FlatConfigComposer<T>;
    /**
     * Resolve the pipeline and return the final configs.
     *
     * This returns a promise. Calling `.then()` has the same effect.
     */
    toConfigs(): Promise<T[]>;
    then(onFulfilled: (value: T[]) => any, onRejected?: (reason: any) => any): Promise<any>;
    catch(onRejected: (reason: any) => any): Promise<any>;
    finally(onFinally: () => any): Promise<T[]>;
}
/**
 * @deprecated Renamed to `composer`.
 */
declare const pipe: typeof composer;
/**
 * @deprecated Renamed to `FlatConfigComposer`.
 */
declare class FlatConfigPipeline<T extends object = Linter.Config, ConfigNames extends string = string> extends FlatConfigComposer<T, ConfigNames> {
}

/**
 * Concat multiple flat configs into a single flat config array.
 *
 * It also resolves promises and flattens the result.
 *
 * @example
 *
 * ```ts
 * import { concat } from 'eslint-flat-config-utils'
 * import eslint from '@eslint/js'
 * import stylistic from '@stylistic/eslint-plugin'
 *
 * export default concat(
 *   eslint,
 *   stylistic.configs.customize(),
 *   { rules: { 'no-console': 'off' } },
 *   // ...
 * )
 * ```
 */
declare function concat<T extends Linter.Config = Linter.Config>(...configs: Awaitable<T | T[]>[]): Promise<T[]>;

/**
 * A function that returns the config as-is, useful for providing type hints.
 */
declare function defineFlatConfig<T extends Linter.Config = Linter.Config>(config: T): T;

/**
 * Extend another flat configs and rename globs paths.
 *
 * @example
 * ```ts
 * import { extend } from 'eslint-flat-config-utils'
 *
 * export default [
 *   ...await extend(
 *     // configs to extend
 *     import('./other-configs/eslint.config.js').then(m => m.default),
 *     // relative directory path
 *     'other-configs/',
 *   ),
 * ]
 * ```
 */
declare function extend(configs: Awaitable<Linter.Config[]>, relativePath: string): Promise<Linter.Config[]>;

/**
 * Replace a rule in a plugin with given factory.
 */
declare function hijackPluginRule(plugin: ESLint.Plugin, name: string, factory: (rule: Rule.RuleModule) => Rule.RuleModule): ESLint.Plugin;
/**
 * Hijack into a rule's `context.report` to disable fixes.
 */
declare function disableRuleFixes(rule: Rule.RuleModule): Rule.RuleModule;

/**
 * Merge multiple flat configs into a single flat config.
 *
 * Note there is no guarantee that the result works the same as the original configs.
 */
declare function mergeConfigs<T extends Linter.Config = Linter.Config>(...configs: T[]): T;

declare function parseRuleId(ruleId: string): {
    plugin: string | null;
    rule: string;
};

/**
 * Rename plugin prefixes in a rule object.
 * Accepts a map of prefixes to rename.
 *
 * @example
 * ```ts
 * import { renamePluginsInRules } from 'eslint-flat-config-utils'
 *
 * export default [{
 *   rules: renamePluginsInRules(
 *     {
 *       '@typescript-eslint/indent': 'error'
 *     },
 *     { '@typescript-eslint': 'ts' }
 *   )
 * }]
 * ```
 */
declare function renamePluginsInRules(rules: Record<string, any>, map: Record<string, string>): Record<string, any>;
/**
 * Rename plugin names a flat configs array
 *
 * @example
 * ```ts
 * import { renamePluginsInConfigs } from 'eslint-flat-config-utils'
 * import someConfigs from './some-configs'
 *
 * export default renamePluginsInConfigs(someConfigs, {
 *   '@typescript-eslint': 'ts',
 *   'import-x': 'import',
 * })
 * ```
 */
declare function renamePluginsInConfigs<T extends Linter.Config = Linter.Config>(configs: T[], map: Record<string, string>): T[];

export { type Arrayable, type Awaitable, DEFAULT_PLUGIN_CONFLICTS_ERROR, type DefaultConfigNamesMap, type DisableFixesOptions, type FilterType, FlatConfigComposer, type FlatConfigItem, FlatConfigPipeline, type GetRuleRecordFromConfig, type NullableObject, type PluginConflictsError, type ResolvableFlatConfig, type StringLiteralUnion, composer, concat, defineFlatConfig, disableRuleFixes, extend, hijackPluginRule, mergeConfigs, parseRuleId, pipe, renamePluginsInConfigs, renamePluginsInRules };
