'use strict';

var chunk3ZX4WMIX_cjs = require('./chunk-3ZX4WMIX.cjs');
var chunk4UERBOUH_cjs = require('./chunk-4UERBOUH.cjs');
var chunkAF3E2D32_cjs = require('./chunk-AF3E2D32.cjs');
var types = require('@storm-software/config-tools/types');
var joinPaths = require('@stryke/path/join-paths');
var packageFns = require('@stryke/fs/package-fns');
var readFile = require('@stryke/fs/read-file');
var semverFns = require('@stryke/fs/semver-fns');
var filePathFns = require('@stryke/path/file-path-fns');
var getParentPath = require('@stryke/path/get-parent-path');
var isFile = require('@stryke/path/is-file');
var isError = require('@stryke/type-checks/is-error');
var path = require('path');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var path__default = /*#__PURE__*/_interopDefault(path);

function pluginCount(messages) {
  let nextPluginWarningCount = 0;
  let nextPluginErrorCount = 0;
  for (let i = 0; i < messages.length; i++) {
    const { severity, ruleId } = messages[i];
    if (ruleId?.includes("storm-stack")) {
      if (severity === 1) {
        nextPluginWarningCount += 1;
      } else {
        nextPluginErrorCount += 1;
      }
    }
  }
  return {
    nextPluginErrorCount,
    nextPluginWarningCount
  };
}
chunkAF3E2D32_cjs.__name(pluginCount, "pluginCount");
function formatMessage(dir, messages, filePath) {
  let fileName = path__default.default.posix.normalize(path__default.default.relative(dir, filePath).replace(/\\/g, "/"));
  if (!fileName.startsWith(".")) {
    fileName = `./${fileName}`;
  }
  let output = `
${fileName}`;
  for (let i = 0; i < messages.length; i++) {
    const { message, severity, line, column, ruleId } = messages[i];
    output += "\n";
    if (line && column) {
      output = `${output + line.toString()}:${column.toString()}  `;
    }
    if (severity === 1) {
      output += `Warning: `;
    } else {
      output += `Error: `;
    }
    output += message;
    if (ruleId) {
      output += `  ${ruleId}`;
    }
  }
  return output;
}
chunkAF3E2D32_cjs.__name(formatMessage, "formatMessage");
async function formatResults(baseDir, results, format) {
  let totalPluginErrorCount = 0;
  let totalPluginWarningCount = 0;
  const resultsWithMessages = results.filter(({ messages }) => messages?.length);
  resultsWithMessages.forEach(({ messages }) => {
    const res = pluginCount(messages);
    totalPluginErrorCount += res.nextPluginErrorCount;
    totalPluginWarningCount += res.nextPluginWarningCount;
  });
  const output = format ? await format(resultsWithMessages) : resultsWithMessages.map(({ messages, filePath }) => formatMessage(baseDir, messages, filePath)).join("\n");
  return {
    output,
    outputWithMessages: resultsWithMessages.length > 0 ? `${output}

Info  - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/app/api-reference/config/eslint#disabling-rules` : "",
    totalPluginErrorCount,
    totalPluginWarningCount
  };
}
chunkAF3E2D32_cjs.__name(formatResults, "formatResults");
async function writeDefaultEslintConfig(log, context, type = "recommended") {
  const eslintConfigFile = joinPaths.joinPaths(context.workspaceConfig.workspaceRoot, "eslint.config.js");
  const eslintConfig = `
import { getConfig } from "eslint-config-storm-stack";

Error.stackTraceLimit = Number.POSITIVE_INFINITY;

export default getConfig({
  repositoryName: "${context.workspaceConfig.name || context.name || "storm-stack"}",
  "storm-stack": "${type}",
});
`;
  log(types.LogLevelLabel.INFO, `Writing a default ESLint config file to ${eslintConfigFile}`);
  return chunk4UERBOUH_cjs.writeFile(log, eslintConfigFile, eslintConfig);
}
chunkAF3E2D32_cjs.__name(writeDefaultEslintConfig, "writeDefaultEslintConfig");

// src/lint/eslint/lint.ts
var VALID_SEVERITY = [
  "off",
  "warn",
  "error"
];
function isValidSeverity(severity) {
  return VALID_SEVERITY.includes(severity);
}
chunkAF3E2D32_cjs.__name(isValidSeverity, "isValidSeverity");
async function writeOutputFile(log, outputFile, outputData) {
  const filePath = path__default.default.resolve(process.cwd(), outputFile);
  if (isFile.isDirectory(filePath)) {
    log(types.LogLevelLabel.ERROR, `Cannot write to output file path, it is a directory: ${filePath}`);
  } else {
    try {
      await chunk4UERBOUH_cjs.writeFile(log, filePath, outputData);
      log(types.LogLevelLabel.INFO, `The output file has been created: ${filePath}`);
    } catch (err) {
      log(types.LogLevelLabel.ERROR, `There was a problem writing the output file: ${filePath}`);
      console.error(err);
    }
  }
}
chunkAF3E2D32_cjs.__name(writeOutputFile, "writeOutputFile");
async function hasEslintConfiguration(eslintFile, packageJsonConfig) {
  const configObject = {
    exists: false,
    emptyEslint: false,
    emptyPkgJsonConfig: false
  };
  if (eslintFile) {
    const content = await readFile.readFile(eslintFile).then((txt) => txt.trim().replace(/\n/g, ""), () => null);
    if (content === "" || content === "{}" || content === "---" || content === "module.exports = {}") {
      configObject.emptyEslint = true;
    } else {
      configObject.exists = true;
    }
  } else if (packageJsonConfig?.eslintConfig) {
    if (Object.keys(packageJsonConfig.eslintConfig).length) {
      configObject.exists = true;
    } else {
      configObject.emptyPkgJsonConfig = true;
    }
  }
  return configObject;
}
chunkAF3E2D32_cjs.__name(hasEslintConfiguration, "hasEslintConfiguration");
async function lint(log, context, eslintrcFile, { lintDuringBuild = false, eslintOptions = null, reportErrorsOnly = false, maxWarnings = -1, formatter = null, outputFile = null }) {
  try {
    await chunk3ZX4WMIX_cjs.installPackages(log, context, [
      {
        name: "eslint",
        dev: true
      },
      {
        name: "eslint-config-storm-stack",
        dev: true
      }
    ]);
    const isInstalled = packageFns.isPackageExists("eslint", {
      paths: [
        context.workspaceConfig.workspaceRoot,
        context.options.projectRoot
      ]
    });
    if (!isInstalled) {
      log(types.LogLevelLabel.ERROR, `ESLint must be installed${lintDuringBuild ? " in order to run during builds:" : ":"} npm install --save-dev eslint`);
      return null;
    }
    const module = await context.resolver.import(context.resolver.esmResolve("eslint"));
    const useFlatConfig = eslintrcFile ? filePathFns.findFileName(eslintrcFile).startsWith("eslint.config.") : false;
    let ESLint;
    if ("loadESLint" in module) {
      ESLint = await module.loadESLint({
        useFlatConfig
      });
    }
    const eslintVersion = semverFns.parseVersion(ESLint?.version);
    if (!eslintVersion || eslintVersion.compare("8.57.0") < 0) {
      return `Error - Your project has an older version of ESLint installed${eslintVersion ? ` (${eslintVersion.major}.${eslintVersion.minor}.${eslintVersion.patch})` : ""}. Please upgrade to ESLint version 8.57.0 or above`;
    }
    const options = {
      useEslintrc: true,
      baseConfig: {},
      errorOnUnmatchedPattern: false,
      extensions: [
        ".js",
        ".jsx",
        ".ts",
        ".tsx"
      ],
      cache: true,
      ...eslintOptions
    };
    if (eslintVersion?.compare("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 stormStackEslintPluginIsEnabled = false;
    const stormStackRulesEnabled = /* @__PURE__ */ new Map();
    for (const configFile of [
      eslintrcFile,
      joinPaths.joinPaths(context.options.projectRoot, "package.json")
    ]) {
      if (!configFile) continue;
      const completeConfig = await eslint.calculateConfigForFile(configFile);
      if (!completeConfig) continue;
      const plugins = completeConfig.plugins;
      const hasStormStackPlugin = (
        // in ESLint < 9, `plugins` value is string[]
        Array.isArray(plugins) ? plugins.includes("storm-stack") : "storm-stack" in plugins
      );
      if (hasStormStackPlugin) {
        stormStackEslintPluginIsEnabled = true;
        for (const [name, [severity]] of Object.entries(completeConfig.rules)) {
          if (!name.startsWith("storm-stack/")) {
            continue;
          }
          if (typeof severity === "number" && severity >= 0 && severity < VALID_SEVERITY.length) {
            stormStackRulesEnabled.set(name, VALID_SEVERITY[severity]);
          } else if (typeof severity === "string" && isValidSeverity(severity)) {
            stormStackRulesEnabled.set(name, severity);
          }
        }
        break;
      }
    }
    if (stormStackEslintPluginIsEnabled) {
      eslint = new ESLint(options);
    } else {
      log(types.LogLevelLabel.WARN, "The Storm Stack 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(context.tsconfig.fileNames.filter((fileName) => !fileName.includes(context.artifactsDir) && !fileName.includes("node_modules")));
    let selectedFormatter = null;
    if (options.fix) {
      await ESLint.outputFixes(results);
    }
    if (reportErrorsOnly) {
      results = ESLint.getErrorResults(results);
    }
    if (formatter) {
      selectedFormatter = await eslint.loadFormatter(formatter);
    }
    const formattedResult = await formatResults(
      context.options.projectRoot,
      results,
      // eslint-disable-next-line ts/unbound-method
      selectedFormatter?.format
    );
    const lintEnd = process.hrtime(lintStart);
    const totalWarnings = results.reduce((sum, file) => sum + file.warningCount, 0);
    if (outputFile) {
      await writeOutputFile(log, outputFile, formattedResult.output);
    }
    return {
      output: formattedResult.outputWithMessages,
      isError: ESLint.getErrorResults(results)?.length > 0 || maxWarnings >= 0 && totalWarnings > maxWarnings,
      eventInfo: {
        durationInSeconds: lintEnd[0],
        eslintVersion: eslintVersion.version,
        lintedFilesCount: results.length,
        lintFix: !!options.fix,
        eslintPluginErrorsCount: formattedResult.totalPluginErrorCount,
        eslintPluginWarningsCount: formattedResult.totalPluginWarningCount,
        stormStackRulesEnabled: Object.fromEntries(stormStackRulesEnabled)
      }
    };
  } catch (err) {
    if (lintDuringBuild) {
      log(types.LogLevelLabel.ERROR, `ESLint: ${isError.isError(err) && err.message ? err.message.replace(/\n/g, " ") : err}`);
      return null;
    } else {
      throw err;
    }
  }
}
chunkAF3E2D32_cjs.__name(lint, "lint");
async function runEslint(log, context, opts = {}) {
  const { lintDuringBuild = false, eslintOptions = null, reportErrorsOnly = false, maxWarnings = -1, formatter = null, outputFile = null, type = "recommended" } = opts;
  const eslintFile = getParentPath.getParentPath([
    // 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"
  ], context.options.projectRoot) ?? null;
  const config = await hasEslintConfiguration(eslintFile, context.packageJson);
  if (config.exists) {
    return lint(log, context, eslintFile, {
      lintDuringBuild,
      eslintOptions,
      reportErrorsOnly,
      maxWarnings,
      formatter,
      outputFile
    });
  }
  if (lintDuringBuild) {
    if (config.emptyPkgJsonConfig || config.emptyEslint) {
      log(types.LogLevelLabel.WARN, `No ESLint configuration detected. Run "storm-stack lint" to begin setup`);
    }
    return null;
  } else {
    const isEslintInstalled = packageFns.isPackageExists("eslint", {
      paths: [
        context.workspaceConfig.workspaceRoot,
        context.options.projectRoot
      ]
    });
    const isEslintPluginInstalled = packageFns.isPackageExists("eslint-config-storm-stack", {
      paths: [
        context.workspaceConfig.workspaceRoot,
        context.options.projectRoot
      ]
    });
    if (!isEslintInstalled || !isEslintPluginInstalled) {
      await chunk3ZX4WMIX_cjs.installPackages(log, context, [
        {
          name: "eslint",
          dev: true
        },
        {
          name: "eslint-config-storm-stack",
          dev: true
        }
      ]);
    }
    await writeDefaultEslintConfig(log, context, type);
  }
  log(types.LogLevelLabel.SUCCESS, `ESLint has successfully been configured. Run "storm-stack lint" again to view warnings and errors.`);
  return null;
}
chunkAF3E2D32_cjs.__name(runEslint, "runEslint");

// src/lint/eslint/index.ts
async function lintEslint(log, context, hooks) {
  log(types.LogLevelLabel.TRACE, `Running ESLint on the Storm Stack project.`);
  await runEslint(log, context, {
    lintDuringBuild: true,
    eslintOptions: {
      cacheLocation: joinPaths.joinPaths(context.envPaths.cache, "eslint")
    }
  });
  await hooks.callHook("lint:eslint", context).catch((error) => {
    log(types.LogLevelLabel.ERROR, `An error occured while running ESLint on the Storm Stack project: ${error.message} 
${error.stack ?? ""}`);
    throw new Error("An error occured while running ESLint on the Storm Stack project", {
      cause: error
    });
  });
}
chunkAF3E2D32_cjs.__name(lintEslint, "lintEslint");

// src/lint/index.ts
async function lint2(log, context, hooks) {
  await hooks.callHook("lint:begin", context).catch((error) => {
    log(types.LogLevelLabel.ERROR, `An error occured while starting the lint process for the Storm Stack project: ${error.message} 
${error.stack ?? ""}`);
    throw new Error("An error occured while starting the lint process for the Storm Stack project", {
      cause: error
    });
  });
  await lintEslint(log, context, hooks);
  await hooks.callHook("lint:complete", context).catch((error) => {
    log(types.LogLevelLabel.ERROR, `An error occured while finishing the lint process for the Storm Stack project: ${error.message} 
${error.stack ?? ""}`);
    throw new Error("An error occured while finishing the lint process for the Storm Stack project", {
      cause: error
    });
  });
}
chunkAF3E2D32_cjs.__name(lint2, "lint");

exports.lint = lint2;
//# sourceMappingURL=chunk-7I2DRUWD.cjs.map
//# sourceMappingURL=chunk-7I2DRUWD.cjs.map