• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

alerque / luacheck / 16694594674

01 Aug 2025 10:34PM UTC coverage: 97.042% (-0.02%) from 97.064%
16694594674

push

github

web-flow
feat: Add standard support for Lua 5.5 (#132) (#133)

...in particular adding support for `table.create`.

19 of 21 new or added lines in 1 file covered. (90.48%)

1 existing line in 1 file now uncovered.

6299 of 6491 relevant lines covered (97.04%)

19288.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.75
/src/luacheck/globbing.lua
1
local fs = require "luacheck.fs"
516✔
2
local utils = require "luacheck.utils"
516✔
3

4
-- Only ?, *, ** and simple character classes (with ranges and negation) are supported.
5
-- Hidden files are not treated specially. Special characters can't be escaped.
6
local globbing = {}
516✔
7

8
local function is_regular_path(glob)
9
   return not glob:find("[*?%[]")
7,800✔
10
end
11

12
local function get_parts(path)
13
   local parts = {}
14,408✔
14

15
   for part in path:gmatch("[^"..utils.dir_sep.."]+") do
112,464✔
16
      table.insert(parts, part)
98,056✔
17
   end
18

19
   return parts
14,408✔
20
end
21

22
local function glob_pattern_escaper(c)
23
   return ((c == "*" or c == "?") and "." or "%")..c
40,172✔
24
end
25

26
local function glob_range_escaper(c)
27
   return c == "-" and c or ("%"..c)
28✔
28
end
29

30
local function glob_part_to_pattern(glob_part)
31
   local buffer = {"^"}
60,008✔
32
   local i = 1
60,008✔
33

34
   while i <= #glob_part do
120,052✔
35
      local bracketless
36
      bracketless, i = glob_part:match("([^%[]*)()", i)
60,044✔
37
      table.insert(buffer, (bracketless:gsub("%p", glob_pattern_escaper)))
60,044✔
38

39
      if glob_part:sub(i, i) == "[" then
60,044✔
40
         table.insert(buffer, "[")
84✔
41
         i = i + 1
84✔
42
         local first_char = glob_part:sub(i, i)
84✔
43

44
         if first_char == "!" then
84✔
45
            table.insert(buffer, "^")
28✔
46
            i = i + 1
28✔
47
         elseif first_char == "]" then
56✔
48
            table.insert(buffer, "%]")
20✔
49
            i = i + 1
20✔
50
         end
51

52
         bracketless, i = glob_part:match("([^%]]*)()", i)
84✔
53

54
         if bracketless:sub(1, 1) == "-" then
84✔
55
            table.insert(buffer, "%-")
12✔
56
            bracketless = bracketless:sub(2)
12✔
57
         end
58

59
         local last_dash = ""
84✔
60

61
         if bracketless:sub(-1) == "-" then
84✔
62
            last_dash = "-"
4✔
63
            bracketless = bracketless:sub(1, -2)
4✔
64
         end
65

66
         table.insert(buffer, (bracketless:gsub("%p", glob_range_escaper)))
84✔
67
         table.insert(buffer, last_dash.."]")
84✔
68
         i = i + 1
84✔
69
      end
70
   end
71

72
   table.insert(buffer, "$")
60,008✔
73
   return table.concat(buffer)
60,008✔
74
end
75

76
local function part_match(glob_part, path_part)
77
   return utils.pmatch(path_part, glob_part_to_pattern(glob_part))
60,008✔
78
end
79

80
local function parts_match(glob_parts, glob_i, path_parts, path_i)
81
   local glob_part = glob_parts[glob_i]
75,416✔
82

83
   if not glob_part then
75,416✔
84
      -- Reached glob end, path matches the glob or its subdirectory.
85
      -- E.g. path "foo/bar/baz/src.lua" matches glob "foo/*/baz".
86
      return true
220✔
87
   end
88

89
   if glob_part == "**" then
75,196✔
90
      -- "**" can consume any number of path parts.
91
      for i = path_i, #path_parts + 1 do
54,672✔
92
         if parts_match(glob_parts, glob_i + 1, path_parts, i) then
47,144✔
93
            return true
132✔
94
         end
95
      end
96

97
      return false
7,528✔
98
   end
99

100
   local path_part = path_parts[path_i]
67,536✔
101
   return path_part and part_match(glob_part, path_part) and (
67,536✔
102
      parts_match(glob_parts, glob_i + 1, path_parts, path_i + 1))
67,536✔
103
end
104

105
-- Checks if a path matches a globbing pattern.
106
-- Both must be absolute.
107
function globbing.match(glob, path)
516✔
108
   if is_regular_path(glob) then
7,800✔
109
      return fs.is_subpath(glob, path)
600✔
110
   end
111

112
   local glob_base, path_base
113
   glob_base, glob = fs.split_base(glob)
7,200✔
114
   path_base, path = fs.split_base(path)
7,200✔
115

116
   if glob_base ~= path_base then
7,200✔
117
      return false
×
118
   end
119

120
   local glob_parts = get_parts(glob)
7,200✔
121
   local path_parts = get_parts(path)
7,200✔
122
   return parts_match(glob_parts, 1, path_parts, 1)
7,200✔
123
end
124

125
-- Checks if glob1 is less specific than glob2 and should be applied
126
-- first in overrides.
127
function globbing.compare(glob1, glob2)
516✔
128
   local base1, base2
129
   base1, glob1 = fs.split_base(glob1)
4✔
130
   base2, glob2 = fs.split_base(glob2)
4✔
131

132
   if base1 ~= base2 then
4✔
133
      return base1 < base2
×
134
   end
135

136
   local parts1 = get_parts(glob1)
4✔
137
   local parts2 = get_parts(glob2)
4✔
138

139
   for i = 1, math.max(#parts1, #parts2) do
32✔
140
      if not parts1[i] then
32✔
141
         return true
3✔
142
      elseif not parts2[i] then
29✔
UNCOV
143
         return false
1✔
144
      end
145

146
      if (parts1[i] == "**" or parts2[i] == "**") and parts1[i] ~= parts2[i] then
28✔
147
         return parts1[i] == "**"
×
148
      end
149

150
      local _, specials1 = parts1[i]:gsub("[%*%?%[]", {})
28✔
151
      local _, specials2 = parts2[i]:gsub("[%*%?%[]", {})
28✔
152

153
      if specials1 ~= specials2 then
28✔
154
         return specials1 > specials2
×
155
      end
156
   end
157

158
   return glob1 < glob2
×
159
end
160

161
return globbing
516✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc