Skip to content

Commit

Permalink
Improve depgraph
Browse files Browse the repository at this point in the history
  • Loading branch information
gaymeowing committed Aug 14, 2024
1 parent e1332e1 commit 33dce15
Showing 1 changed file with 60 additions and 67 deletions.
127 changes: 60 additions & 67 deletions scripts/depgraph.luau
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
-- module for generating a dependency graph for all libraries

local remove_from_end = require("remove_from_end")
local require_pattern = require("require_pattern")
local iter_scripts = require("iter_scripts")
local process = require("@lune/process")
local ends_with = require("ends_with")
local remove = require("remove")
local fs = require("@lune/fs")

export type DependencyInfo = {
Expand All @@ -15,30 +17,11 @@ export type DependencyInfo = {
deep: { string },
}

local REQUIRE_PATTERN = "local%s+%w+%s*=%s*require%s*%(%-?%-?%-?[\"'`](.-)[\"'`]%)"
local GRAPH = {} :: { [string]: DependencyInfo }
local LINE_PATTERN = "[^\r\n]+"
local FOUND = {} :: { [string]: boolean }
local DEPQUEUE = {} :: { string }
local GMATCH = string.gmatch
local MATCH = string.match
local SUB = string.sub

local function REMOVE_OR_ERROR<V>(t: { V }, index: number?): V
local value = table.remove(t, index)

if not value then
error("this is supposed to be unreachable")
end
return value
end

local function find_lib_in_relative_path(path: string): string?
local found_lib = MATCH(remove_from_end(path, "/init"), "([^/]+)$")

return if found_lib and GRAPH[found_lib] then
found_lib
else
nil
end

for _, lib in fs.readDir("libs") do
GRAPH[lib] = {
Expand All @@ -49,69 +32,79 @@ for _, lib in fs.readDir("libs") do
end

for lib, depinfo in GRAPH do
local dirqueue = { `libs/{lib}` }
local shallow = depinfo.shallow

while #dirqueue ~= 0 do
local current_dir = REMOVE_OR_ERROR(dirqueue, 1)

for _, entry in fs.readDir(current_dir) do
local entry_path = `{current_dir}/{entry}`

if ends_with(entry, ".luau") then
local contents = fs.readFile(entry_path)

for require_path in GMATCH(contents, REQUIRE_PATTERN) do
local deplib = find_lib_in_relative_path(require_path)

if deplib and not table.find(shallow, deplib) then
table.insert(shallow, deplib)
end
end
elseif fs.isDir(entry_path) then
table.insert(dirqueue, entry_path)
end
end
end

iter_scripts(`libs/{lib}`, function(_, src)
for require_path in GMATCH(src, require_pattern) do
local deplib = MATCH(remove_from_end(require_path, "/init"), "([^/]+)$")

if deplib and GRAPH[deplib] and not table.find(shallow, deplib) then
table.insert(shallow, deplib)
end
end
return nil
end)
end

for lib, depinfo in GRAPH do
local shallow = depinfo.shallow
local depqueue = table.clone(depinfo.shallow)
local shallow_len = #shallow
local deep = depinfo.deep
local found = {}

while #depqueue ~= 0 do
local current = REMOVE_OR_ERROR(depqueue, 1)

if shallow_len ~= 0 then
local queue_len = shallow_len
table.move(shallow, 1, queue_len, 1, DEPQUEUE)

while queue_len ~= 0 do
local current = remove(DEPQUEUE, queue_len)
queue_len -= 1

if not found[current] then
table.insert(deep, current)
found[current] = true
if not FOUND[current] then
table.insert(deep, current)
FOUND[current] = true

-- Add the shallow dependencies of the current item to the queue
for _, dep in GRAPH[current].shallow do
table.insert(depqueue, dep)
end
end
end

if #deep == #shallow then
-- Add the shallow dependencies of the current item to the queue
for _, dep in GRAPH[current].shallow do
queue_len += 1
DEPQUEUE[queue_len] = dep
end
end
end

depinfo.has_deps = true
table.clear(DEPQUEUE)
table.clear(FOUND)
end

if #deep == shallow_len then
depinfo.deep = table.freeze(shallow)
else
table.freeze(shallow)
table.freeze(deep)
end
end

for _, depinfo in GRAPH do
if #depinfo.shallow ~= 0 then
depinfo.has_deps = true
end
table.freeze(depinfo)
end

if process.args[1] == "print" then
print(GRAPH)
local pretty_graph = {} :: { [string]: { shallow: { string }, deep: { string } } | { string } }

for lib, depinfo in GRAPH do
local shallow = depinfo.shallow
local deep = depinfo.deep

if depinfo.has_deps then
if shallow ~= deep then
pretty_graph[lib] = {
shallow = shallow,
deep = deep,
}
else
pretty_graph[lib] = shallow
end
end
end
print(pretty_graph)
end

return table.freeze(GRAPH)

0 comments on commit 33dce15

Please sign in to comment.