/usr/share/lua/5.1/luacheck/options.lua is in lua-check 0.21.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 | local options = {}
local builtin_standards = require "luacheck.builtin_standards"
local standards = require "luacheck.standards"
local utils = require "luacheck.utils"
local boolean = utils.has_type("boolean")
local array_of_strings = utils.array_of("string")
function options.split_std(std)
local parts = utils.split(std, "+")
if parts[1]:match("^%s*$") then
parts.add = true
table.remove(parts, 1)
end
for i, part in ipairs(parts) do
parts[i] = utils.strip(part)
if not builtin_standards[parts[i]] then
return
end
end
return parts
end
local function std_or_array_of_strings(x)
return (type(x) == "string" and options.split_std(x)) or standards.validate_std_table(x)
end
local function field_map(x)
return standards.validate_std_table({globals = x})
end
local function number_or_false(x)
return x == false or type(x) == "number"
end
function options.add_order(option_set)
local opts = {}
for option in pairs(option_set) do
if type(option) == "string" then
table.insert(opts, option)
end
end
table.sort(opts)
utils.update(option_set, opts)
end
options.nullary_inline_options = {
global = boolean,
unused = boolean,
redefined = boolean,
unused_args = boolean,
unused_secondaries = boolean,
self = boolean,
compat = boolean,
allow_defined = boolean,
allow_defined_top = boolean,
module = boolean
}
options.variadic_inline_options = {
globals = field_map,
read_globals = field_map,
new_globals = field_map,
new_read_globals = field_map,
not_globals = array_of_strings,
ignore = array_of_strings,
enable = array_of_strings,
only = array_of_strings
}
options.all_options = {
std = std_or_array_of_strings,
max_line_length = number_or_false,
max_code_line_length = number_or_false,
max_string_line_length = number_or_false,
max_comment_line_length = number_or_false,
inline = boolean
}
utils.update(options.all_options, options.nullary_inline_options)
utils.update(options.all_options, options.variadic_inline_options)
options.add_order(options.all_options)
-- Returns true if opts is valid option_set.
-- Otherwise returns false and, optionally, name of the problematic option.
function options.validate(option_set, opts)
if opts == nil then
return true
end
local ok, is_valid, invalid_opt = pcall(function()
assert(type(opts) == "table")
for _, option in ipairs(option_set) do
if opts[option] ~= nil then
if not option_set[option](opts[option]) then
return false, option
end
end
end
return true
end)
return ok and is_valid, invalid_opt
end
-- Option stack is an array of options with options closer to end
-- overriding options closer to beginning.
-- Extracts sequence of active std tables from an option stack.
local function get_std_tables(opts_stack)
local base_std
local add_stds = {}
local no_compat = false
for _, opts in utils.ripairs(opts_stack) do
if opts.compat and not no_compat then
base_std = builtin_standards.max
break
elseif opts.compat == false then
no_compat = true
end
if opts.std then
if type(opts.std) == "table" then
base_std = opts.std
break
else
local parts = options.split_std(opts.std)
for _, part in ipairs(parts) do
table.insert(add_stds, builtin_standards[part])
end
if not parts.add then
base_std = {}
break
end
end
end
end
table.insert(add_stds, 1, base_std or builtin_standards._G)
return add_stds
end
-- Returns index of the last option table in a stack that uses given option,
-- or zero if the option isn't used anywhere.
local function index_of_last_option_usage(opts_stack, option_name)
for index, opts in utils.ripairs(opts_stack) do
if opts[option_name] then
return index
end
end
return 0
end
local function split_field(field_name)
return utils.split(field_name, "%.")
end
local function field_comparator(field1, field2)
local parts1 = field1[1]
local parts2 = field2[1]
for i = 1, math.max(#parts1, #parts2) do
local part1 = parts1[i]
local part2 = parts2[i]
if not part1 then
return true
elseif not part2 then
return false
end
if part1 ~= part2 then
return part1 < part2
end
end
return false
end
-- Combine all stds and global related options into one final definition table.
-- A definition table may have fields `read_only` (boolean), `other_fields` (boolean),
-- and `fields` (maps field names to definition tables).
-- Std table format is similar, except at the top level there are two fields
-- `globals` and `read_globals` mapping to top-level field tables. Also in field tables
-- it's possible to use field names in array part as a shortcut:
-- `{fields = {"foo"}}` is equivalent to `{fields = {foo = {}}}` or `{fields = {foo = {other_fields = true}}}`
-- in top level fields tables.
local function get_final_std(opts_stack)
local final_std = {}
local std_tables = get_std_tables(opts_stack)
for _, std_table in ipairs(std_tables) do
standards.add_std_table(final_std, std_table)
end
local last_new_globals = index_of_last_option_usage(opts_stack, "new_globals")
local last_new_read_globals = index_of_last_option_usage(opts_stack, "new_read_globals")
for index, opts in ipairs(opts_stack) do
local globals = (index >= last_new_globals) and (opts.new_globals or opts.globals)
local read_globals = (index >= last_new_read_globals) and (opts.new_read_globals or opts.read_globals)
local new_fields = {}
if globals then
for _, global in ipairs(globals) do
table.insert(new_fields, {split_field(global), false})
end
end
if read_globals then
for _, read_global in ipairs(read_globals) do
table.insert(new_fields, {split_field(read_global), true})
end
end
if globals and read_globals then
-- If there are both globals and read-only globals defined in one options table,
-- it's important that more general definitions are applied first,
-- otherwise they will completely overwrite more specific definitions.
-- E.g. `globals x` should be applied before `read globals x.y`.
table.sort(new_fields, field_comparator)
end
for _, field in ipairs(new_fields) do
standards.overwrite_field(final_std, field[1], field[2])
end
standards.add_std_table(final_std, {globals = globals, read_globals = read_globals}, true, true)
if opts.not_globals then
for _, not_global in ipairs(opts.not_globals) do
standards.remove_field(final_std, split_field(not_global))
end
end
end
standards.finalize(final_std)
return final_std
end
local function get_scalar_opt(opts_stack, option, default)
for _, opts in utils.ripairs(opts_stack) do
if opts[option] ~= nil then
return opts[option]
end
end
return default
end
local line_length_suboptions = {"max_code_line_length", "max_string_line_length", "max_comment_line_length"}
local function get_max_line_opts(opts_stack)
local res = {max_line_length = 120}
for _, opt_name in ipairs(line_length_suboptions) do
res[opt_name] = res.max_line_length
end
for _, opts in ipairs(opts_stack) do
if opts.max_line_length ~= nil then
res.max_line_length = opts.max_line_length
for _, opt_name in ipairs(line_length_suboptions) do
res[opt_name] = opts.max_line_length
end
end
for _, opt_name in ipairs(line_length_suboptions) do
if opts[opt_name] ~= nil then
res[opt_name] = opts[opt_name]
end
end
end
return res
end
local function anchor_pattern(pattern, only_start)
if not pattern then
return
end
if pattern:sub(1, 1) == "^" or pattern:sub(-1) == "$" then
return pattern
else
return "^" .. pattern .. (only_start and "" or "$")
end
end
-- Returns {pair of normalized patterns for code and name}.
-- `pattern` can be:
-- string containing '/': first part matches warning code, second - variable name;
-- string containing letters: matches variable name;
-- otherwise: matches warning code.
-- Unless anchored by user, pattern for name is anchored from both sides
-- and pattern for code is only anchored at the beginning.
local function normalize_pattern(pattern)
local code_pattern, name_pattern
local slash_pos = pattern:find("/")
if slash_pos then
code_pattern = pattern:sub(1, slash_pos - 1)
name_pattern = pattern:sub(slash_pos + 1)
elseif pattern:find("[_a-zA-Z]") then
name_pattern = pattern
else
code_pattern = pattern
end
return {anchor_pattern(code_pattern, true), anchor_pattern(name_pattern)}
end
-- From most specific to less specific, pairs {option, pattern}.
-- Applying macros in order is required to get deterministic results
-- and get sensible results when intersecting macros are used.
-- E.g. unused = false, unused_args = true should leave unused args enabled.
local macros = {
{"unused_args", "21[23]"},
{"global", "1"},
{"unused", "[23]"},
{"redefined", "4"}
}
-- Returns array of rules which should be applied in order.
-- A rule is a table {{pattern*}, type}.
-- `pattern` is a non-normalized pattern.
-- `type` can be "enable", "disable" or "only".
local function get_rules(opts_stack)
local rules = {}
local used_macros = {}
for _, opts in utils.ripairs(opts_stack) do
for _, macro_info in ipairs(macros) do
local option, pattern = macro_info[1], macro_info[2]
if not used_macros[option] then
if opts[option] ~= nil then
table.insert(rules, {{pattern}, opts[option] and "enable" or "disable"})
used_macros[option] = true
end
end
end
if opts.ignore then
table.insert(rules, {opts.ignore, "disable"})
end
if opts.only then
table.insert(rules, {opts.only, "only"})
end
if opts.enable then
table.insert(rules, {opts.enable, "enable"})
end
end
return rules
end
local function normalize_patterns(rules)
local res = {}
for i, rule in ipairs(rules) do
res[i] = {{}, rule[2]}
for j, pattern in ipairs(rule[1]) do
res[i][1][j] = normalize_pattern(pattern)
end
end
return res
end
local scalar_options = {
unused_secondaries = true,
self = true,
inline = true,
module = false,
allow_defined = false,
allow_defined_top = false
}
-- Returns normalized options.
-- Normalized options have fields:
-- std: normalized std table, see `luacheck.standards` module;
-- unused_secondaries, self, inline, module, allow_defined, allow_defined_top: booleans;
-- max_line_length: number or false;
-- rules: see get_rules.
function options.normalize(opts_stack)
local res = {}
res.std = get_final_std(opts_stack)
for option, default in pairs(scalar_options) do
res[option] = get_scalar_opt(opts_stack, option, default)
end
local max_line_opts = get_max_line_opts(opts_stack)
utils.update(res, max_line_opts)
res.rules = normalize_patterns(get_rules(opts_stack))
return res
end
return options
|