local utils = require "luacheck.utils"

local stages = {}

-- Checking is organized into stages run one after another.
-- Each stage is in its own module and provides `run` function operating on a check state,
-- and optionally `warnings` table mapping issue codes to tables with fields `message_format`
-- containing format string for the issue or a function returning it given the issue,
-- and `fields` containing array of extra fields this warning can have.

stages.names = {
   "parse",
   "unwrap_parens",
   "linearize",
   "parse_inline_options",
   "name_functions",
   "resolve_locals",
   "detect_bad_whitespace",
   "detect_cyclomatic_complexity",
   "detect_empty_blocks",
   "detect_empty_statements",
   "detect_globals",
   "detect_reversed_fornum_loops",
   "detect_unbalanced_assignments",
   "detect_uninit_accesses",
   "detect_unreachable_code",
   "detect_unused_fields",
   "detect_unused_locals"
}

stages.modules = {}

for _, name in ipairs(stages.names) do
   table.insert(stages.modules, (require("luacheck.stages." .. name)))
end

stages.warnings = {}

local base_fields = {"code", "line", "column", "end_column"}

local function register_warnings(warnings)
   for code, warning in pairs(warnings) do
      assert(not stages.warnings[code])
      assert(warning.message_format)
      assert(warning.fields)

      local full_fields = utils.concat_arrays({base_fields, warning.fields})

      stages.warnings[code] = {
         message_format = warning.message_format,
         fields = full_fields,
         fields_set = utils.array_to_set(full_fields)
      }
   end
end

-- Issues that do not originate from normal check stages (excluding global related ones).
register_warnings({
   ["011"] = {message_format = "{msg}", fields = {"msg", "prev_line", "prev_column", "prev_end_column"}},
   ["631"] = {message_format = "line is too long ({end_column} > {max_length})", fields = {}}
})

for _, stage_module in ipairs(stages.modules) do
   if stage_module.warnings then
      register_warnings(stage_module.warnings)
   end
end

function stages.run(chstate)
   for _, stage_module in ipairs(stages.modules) do
      stage_module.run(chstate)
   end
end

return stages
