"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "runLintCheck", {
    enumerable: true,
    get: function() {
        return runLintCheck;
    }
});
const _fs = require("fs");
const _picocolors = require("../picocolors");
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _findup = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/find-up"));
const _semver = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/semver"));
const _commentjson = /*#__PURE__*/ _interop_require_wildcard(require("next/dist/compiled/comment-json"));
const _customFormatter = require("./customFormatter");
const _writeDefaultConfig = require("./writeDefaultConfig");
const _hasEslintConfiguration = require("./hasEslintConfiguration");
const _writeOutputFile = require("./writeOutputFile");
const _findpagesdir = require("../find-pages-dir");
const _installdependencies = require("../install-dependencies");
const _hasnecessarydependencies = require("../has-necessary-dependencies");
const _log = /*#__PURE__*/ _interop_require_wildcard(require("../../build/output/log"));
const _iserror = /*#__PURE__*/ _interop_require_wildcard(require("../is-error"));
const _getpkgmanager = require("../helpers/get-pkg-manager");
const _getESLintPromptValues = require("./getESLintPromptValues");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
function _getRequireWildcardCache(nodeInterop) {
    if (typeof WeakMap !== "function") return null;
    var cacheBabelInterop = new WeakMap();
    var cacheNodeInterop = new WeakMap();
    return (_getRequireWildcardCache = function(nodeInterop) {
        return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
    })(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
    if (!nodeInterop && obj && obj.__esModule) {
        return obj;
    }
    if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
        return {
            default: obj
        };
    }
    var cache = _getRequireWildcardCache(nodeInterop);
    if (cache && cache.has(obj)) {
        return cache.get(obj);
    }
    var newObj = {
        __proto__: null
    };
    var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
    for(var key in obj){
        if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
            var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
            if (desc && (desc.get || desc.set)) {
                Object.defineProperty(newObj, key, desc);
            } else {
                newObj[key] = obj[key];
            }
        }
    }
    newObj.default = obj;
    if (cache) {
        cache.set(obj, newObj);
    }
    return newObj;
}
// 0 is off, 1 is warn, 2 is error. See https://eslint.org/docs/user-guide/configuring/rules#configuring-rules
const VALID_SEVERITY = [
    'off',
    'warn',
    'error'
];
function isValidSeverity(severity) {
    return VALID_SEVERITY.includes(severity);
}
const requiredPackages = [
    {
        file: 'eslint',
        pkg: 'eslint',
        exportsRestrict: false
    },
    {
        file: 'eslint-config-next',
        pkg: 'eslint-config-next',
        exportsRestrict: false
    }
];
async function cliPrompt(cwd) {
    console.log((0, _picocolors.bold)(`${(0, _picocolors.cyan)('?')} How would you like to configure ESLint? https://nextjs.org/docs/app/api-reference/config/eslint`));
    try {
        const cliSelect = (await Promise.resolve(require('next/dist/compiled/cli-select'))).default;
        const { value } = await cliSelect({
            values: await (0, _getESLintPromptValues.getESLintPromptValues)(cwd),
            valueRenderer: ({ title, recommended }, selected)=>{
                const name = selected ? (0, _picocolors.bold)((0, _picocolors.underline)((0, _picocolors.cyan)(title))) : title;
                return name + (recommended ? (0, _picocolors.bold)((0, _picocolors.yellow)(' (recommended)')) : '');
            },
            selected: (0, _picocolors.cyan)('❯ '),
            unselected: '  '
        });
        return {
            config: (value == null ? void 0 : value.config) ?? null
        };
    } catch  {
        return {
            config: null
        };
    }
}
async function lint(baseDir, lintDirs, eslintrcFile, pkgJsonPath, { lintDuringBuild = false, eslintOptions = null, reportErrorsOnly = false, maxWarnings = -1, formatter = null, outputFile = null }) {
    try {
        var _mod_CLIEngine, _ESLint_getErrorResults;
        // Load ESLint after we're sure it exists:
        const deps = await (0, _hasnecessarydependencies.hasNecessaryDependencies)(baseDir, requiredPackages);
        const packageManager = (0, _getpkgmanager.getPkgManager)(baseDir);
        if (deps.missing.some((dep)=>dep.pkg === 'eslint')) {
            _log.error(`ESLint must be installed${lintDuringBuild ? ' in order to run during builds:' : ':'} ${(0, _picocolors.bold)((0, _picocolors.cyan)((packageManager === 'yarn' ? 'yarn add --dev' : packageManager === 'pnpm' ? 'pnpm install --save-dev' : 'npm install --save-dev') + ' eslint'))}`);
            return null;
        }
        const mod = await Promise.resolve(require(deps.resolved.get('eslint')));
        // If V9 config was found, use flat config, or else use legacy.
        const useFlatConfig = eslintrcFile ? _path.default.basename(eslintrcFile).startsWith('eslint.config.') : false;
        let ESLint;
        // loadESLint is >= 8.57.0
        // PR https://github.com/eslint/eslint/pull/18098
        // Release https://github.com/eslint/eslint/releases/tag/v8.57.0
        if ('loadESLint' in mod) {
            // By default, configType is `flat`. If `useFlatConfig` is false, the return value is `LegacyESLint`.
            // https://github.com/eslint/eslint/blob/1def4cdfab1f067c5089df8b36242cdf912b0eb6/lib/types/index.d.ts#L1609-L1613
            ESLint = await mod.loadESLint({
                useFlatConfig
            });
        } else {
            // eslint < 8.57.0, use legacy ESLint
            ESLint = mod.ESLint;
        }
        let eslintVersion = (ESLint == null ? void 0 : ESLint.version) ?? ((_mod_CLIEngine = mod.CLIEngine) == null ? void 0 : _mod_CLIEngine.version);
        if (!eslintVersion || _semver.default.lt(eslintVersion, '7.0.0')) {
            return `${(0, _picocolors.red)('error')} - Your project has an older version of ESLint installed${eslintVersion ? ' (' + eslintVersion + ')' : ''}. Please upgrade to ESLint version 7 or above`;
        }
        let options = {
            useEslintrc: true,
            baseConfig: {},
            errorOnUnmatchedPattern: false,
            extensions: [
                '.js',
                '.jsx',
                '.ts',
                '.tsx'
            ],
            cache: true,
            ...eslintOptions
        };
        if (_semver.default.gte(eslintVersion, '9.0.0') && useFlatConfig) {
            for (const option of [
                'useEslintrc',
                'extensions',
                'ignorePath',
                'reportUnusedDisableDirectives',
                'resolvePluginsRelativeTo',
                'rulePaths',
                'inlineConfig',
                'maxWarnings'
            ]){
                if (option in options) {
                    delete options[option];
                }
            }
        }
        let eslint = new ESLint(options);
        let nextEslintPluginIsEnabled = false;
        const nextRulesEnabled = new Map();
        for (const configFile of [
            eslintrcFile,
            pkgJsonPath
        ]){
            if (!configFile) continue;
            const completeConfig = await eslint.calculateConfigForFile(configFile);
            if (!completeConfig) continue;
            const plugins = completeConfig.plugins;
            const hasNextPlugin = // in ESLint < 9, `plugins` value is string[]
            Array.isArray(plugins) ? plugins.includes('@next/next') : '@next/next' in plugins;
            if (hasNextPlugin) {
                nextEslintPluginIsEnabled = true;
                for (const [name, [severity]] of Object.entries(completeConfig.rules)){
                    if (!name.startsWith('@next/next/')) {
                        continue;
                    }
                    if (typeof severity === 'number' && severity >= 0 && severity < VALID_SEVERITY.length) {
                        nextRulesEnabled.set(name, VALID_SEVERITY[severity]);
                    } else if (typeof severity === 'string' && isValidSeverity(severity)) {
                        nextRulesEnabled.set(name, severity);
                    }
                }
                break;
            }
        }
        const pagesDir = (0, _findpagesdir.findPagesDir)(baseDir).pagesDir;
        const pagesDirRules = pagesDir ? [
            '@next/next/no-html-link-for-pages'
        ] : [];
        if (nextEslintPluginIsEnabled) {
            let updatedPagesDir = false;
            for (const rule of pagesDirRules){
                var _options_baseConfig_rules, _options_baseConfig_rules1;
                if (!((_options_baseConfig_rules = options.baseConfig.rules) == null ? void 0 : _options_baseConfig_rules[rule]) && !((_options_baseConfig_rules1 = options.baseConfig.rules) == null ? void 0 : _options_baseConfig_rules1[rule.replace('@next/next', '@next/babel-plugin-next')])) {
                    if (!options.baseConfig.rules) {
                        options.baseConfig.rules = {};
                    }
                    options.baseConfig.rules[rule] = [
                        1,
                        pagesDir
                    ];
                    updatedPagesDir = true;
                }
            }
            if (updatedPagesDir) {
                eslint = new ESLint(options);
            }
        } else {
            _log.warn('');
            _log.warn('The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/app/api-reference/config/eslint#migrating-existing-config');
        }
        const lintStart = process.hrtime();
        let results = await eslint.lintFiles(lintDirs);
        let selectedFormatter = null;
        if (options.fix) await ESLint.outputFixes(results);
        if (reportErrorsOnly) results = await ESLint.getErrorResults(results) // Only return errors if --quiet flag is used
        ;
        if (formatter) selectedFormatter = await eslint.loadFormatter(formatter);
        const formattedResult = await (0, _customFormatter.formatResults)(baseDir, results, selectedFormatter == null ? void 0 : selectedFormatter.format);
        const lintEnd = process.hrtime(lintStart);
        const totalWarnings = results.reduce((sum, file)=>sum + file.warningCount, 0);
        if (outputFile) await (0, _writeOutputFile.writeOutputFile)(outputFile, formattedResult.output);
        return {
            output: formattedResult.outputWithMessages,
            isError: ((_ESLint_getErrorResults = ESLint.getErrorResults(results)) == null ? void 0 : _ESLint_getErrorResults.length) > 0 || maxWarnings >= 0 && totalWarnings > maxWarnings,
            eventInfo: {
                durationInSeconds: lintEnd[0],
                eslintVersion: eslintVersion,
                lintedFilesCount: results.length,
                lintFix: !!options.fix,
                nextEslintPluginVersion: nextEslintPluginIsEnabled && deps.resolved.has('eslint-config-next') ? require(_path.default.join(_path.default.dirname(deps.resolved.get('eslint-config-next')), 'package.json')).version : null,
                nextEslintPluginErrorsCount: formattedResult.totalNextPluginErrorCount,
                nextEslintPluginWarningsCount: formattedResult.totalNextPluginWarningCount,
                nextRulesEnabled: Object.fromEntries(nextRulesEnabled)
            }
        };
    } catch (err) {
        if (lintDuringBuild) {
            _log.error(`ESLint: ${(0, _iserror.default)(err) && err.message ? err.message.replace(/\n/g, ' ') : err}`);
            return null;
        } else {
            throw (0, _iserror.getProperError)(err);
        }
    }
}
async function runLintCheck(baseDir, lintDirs, opts) {
    const { lintDuringBuild = false, eslintOptions = null, reportErrorsOnly = false, maxWarnings = -1, formatter = null, outputFile = null, strict = false } = opts;
    try {
        // Find user's .eslintrc file
        // See: https://eslint.org/docs/user-guide/configuring/configuration-files#configuration-file-formats
        const eslintrcFile = await (0, _findup.default)([
            // eslint v9
            'eslint.config.js',
            'eslint.config.mjs',
            'eslint.config.cjs',
            // TS extensions require to install a separate package `jiti`.
            // https://eslint.org/docs/latest/use/configure/configuration-files#typescript-configuration-files
            'eslint.config.ts',
            'eslint.config.mts',
            'eslint.config.cts',
            // eslint <= v8
            '.eslintrc.js',
            '.eslintrc.cjs',
            '.eslintrc.yaml',
            '.eslintrc.yml',
            '.eslintrc.json',
            '.eslintrc'
        ], {
            cwd: baseDir
        }) ?? null;
        const pkgJsonPath = await (0, _findup.default)('package.json', {
            cwd: baseDir
        }) ?? null;
        let packageJsonConfig = null;
        if (pkgJsonPath) {
            const pkgJsonContent = await _fs.promises.readFile(pkgJsonPath, {
                encoding: 'utf8'
            });
            packageJsonConfig = _commentjson.parse(pkgJsonContent);
        }
        const config = await (0, _hasEslintConfiguration.hasEslintConfiguration)(eslintrcFile, packageJsonConfig);
        let deps;
        if (config.exists) {
            // Run if ESLint config exists
            return await lint(baseDir, lintDirs, eslintrcFile, pkgJsonPath, {
                lintDuringBuild,
                eslintOptions,
                reportErrorsOnly,
                maxWarnings,
                formatter,
                outputFile
            });
        } else {
            // Display warning if no ESLint configuration is present inside
            // config file during "next build", no warning is shown when
            // no eslintrc file is present
            if (lintDuringBuild) {
                if (config.emptyPkgJsonConfig || config.emptyEslintrc) {
                    _log.warn(`No ESLint configuration detected. Run ${(0, _picocolors.bold)((0, _picocolors.cyan)('next lint'))} to begin setup`);
                }
                return null;
            } else {
                // Ask user what config they would like to start with for first time "next lint" setup
                const { config: selectedConfig } = strict ? await (0, _getESLintPromptValues.getESLintStrictValue)(baseDir) : await cliPrompt(baseDir);
                if (selectedConfig == null) {
                    // Show a warning if no option is selected in prompt
                    _log.warn('If you set up ESLint yourself, we recommend adding the Next.js ESLint plugin. See https://nextjs.org/docs/app/api-reference/config/eslint#migrating-existing-config');
                    return null;
                } else {
                    // Check if necessary deps installed, and install any that are missing
                    deps = await (0, _hasnecessarydependencies.hasNecessaryDependencies)(baseDir, requiredPackages);
                    if (deps.missing.length > 0) {
                        deps.missing.forEach((dep)=>{
                            if (dep.pkg === 'eslint') {
                                // pin to v9 to avoid breaking changes
                                dep.pkg = 'eslint@^9';
                            }
                        });
                        await (0, _installdependencies.installDependencies)(baseDir, deps.missing, true);
                    }
                    // Write default ESLint config.
                    // Check for /pages and src/pages is to make sure this happens in Next.js folder
                    if ([
                        'app',
                        'src/app',
                        'pages',
                        'src/pages'
                    ].some((dir)=>(0, _fs.existsSync)(_path.default.join(baseDir, dir)))) {
                        await (0, _writeDefaultConfig.writeDefaultConfig)(baseDir, config, selectedConfig, eslintrcFile, pkgJsonPath, packageJsonConfig);
                    }
                }
                _log.ready(`ESLint has successfully been configured. Run ${(0, _picocolors.bold)((0, _picocolors.cyan)('next lint'))} again to view warnings and errors.`);
                return null;
            }
        }
    } catch (err) {
        throw err;
    }
}

//# sourceMappingURL=runLintCheck.js.map