-- The configuration for the static analyzer explcheck. local toml = require("explcheck-toml") local utils = require("explcheck-utils") -- Read a TOML file with a user-defined configuration. local function read_config_file(pathname) local file = io.open(pathname, "r") if file == nil then return nil end local content = assert(file:read("*a")) assert(file:close()) return toml.parse(content) end -- Load the default configuration from the pre-installed config file `explcheck-config.toml`. local default_config_pathname = string.sub(debug.getinfo(1).source, 2, (#".lua" + 1) * -1) .. ".toml" local default_config = read_config_file(default_config_pathname) assert(default_config ~= nil) local user_configs = {} -- Try to load user-defined configuration. local function get_user_config(options) -- Read the configuration. local default_pathname, options_pathname default_pathname = default_config.defaults["config_file"] assert(default_pathname ~= nil) if options ~= nil and options["config_file"] ~= nil then options_pathname = options["config_file"] end -- Determine the pathname of the user-defined config file. local pathname, must_exist if options_pathname ~= nil then pathname = options_pathname must_exist = options_pathname ~= default_pathname -- if the options specify a distinct pathname, it must exist else pathname = default_pathname must_exist = false end assert(pathname ~= nil) -- Try to read the configuration. if user_configs[pathname] == nil then user_configs[pathname] = read_config_file(pathname) -- only read the file from the disk once end if user_configs[pathname] == nil or user_configs[pathname] == false then if must_exist then error(string.format('Config file "%s" does not exist', pathname)) end user_configs[pathname] = false -- mark the file as read, so that we don't read it again return nil else return user_configs[pathname], pathname end end -- Get the filename of a file. local function get_filename(pathname) return utils.get_basename(pathname) end -- Get the package name of a file. local function get_package(pathname) return utils.get_basename(utils.get_parent(pathname)) end -- Get the value of an option. local function get_option(key, options, pathname) -- If a table of options is provided and the option is specified there, use it. if options ~= nil and options[key] ~= nil then return options[key] end -- Otherwise, try and load the user-defined configuration. local configs local user_config = get_user_config(options) if user_config ~= nil then configs = {user_config, default_config} else configs = {default_config} end -- Then, try the user-defined configuration first, if it exists, and then the default configuration. for _, config in ipairs(configs) do if pathname ~= nil then -- If a pathname is provided and the current configuration specifies the option for this filename, use it. local filename = get_filename(pathname) if config.filename ~= nil and config.filename[filename] ~= nil and config.filename[filename][key] ~= nil then return config.filename[filename][key] end -- If a pathname is provided and the current configuration specifies the option for this package, use it. local package = get_package(pathname) if config.package ~= nil and config.package[package] ~= nil and config.package[package][key] ~= nil then return config.package[package][key] end end -- If the current configuration specifies the option in the defaults, use it. for _, section in ipairs({"defaults", "options"}) do -- TODO: Remove `[options]` in v1.0.0. if config[section] ~= nil and config[section][key] ~= nil then return config[section][key] end end end error('Failed to get a value for option "' .. key .. '"') end return { default_config = default_config, default_config_pathname = default_config_pathname, get_filename = get_filename, get_option = get_option, get_package = get_package, get_user_config = get_user_config, }