local r=script.Parent local H=require(script.Parent.ScriptInfoUtils)local o=require(script.Parent.LoaderUtils)local S=require(script.Parent.BounceTemplateUtils)local d={}d.ClassName="\083\116\097\116\105\099\076\101\103\097\099\121\076\111\097\100\101\114"d.__index=d function d.new()local r=setmetatable({_packageLookups={}},d)return r end function d.__call(H,r)return H:Require(r)end function d.Lock(r)error("\067\097\110\110\111\116 \115\116\097\114\116 \108\111\097\100\101\114 \119\104\105\108\101 \110\111\116 \114\117\110\110\105\110\103")end function d.Require(o,r,H)if type(H)=="\110\117\109\098\101\114"then return require(H)elseif type(H)=="\115\116\114\105\110\103"then local S=o:_findModule(r,H)if S then o:_ensureFakeLoader(S)return require(S)else error("\069\114\114\111\114\058 \076\105\098\114\097\114\121 \'"..(tostring(H).."\' \100\111\101\115 \110\111\116 \101\120\105\115\116\046"),2)end elseif typeof(H)=="\073\110\115\116\097\110\099\101"and H:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")then return require(H)else error(("\069\114\114\111\114\058 \109\111\100\117\108\101 \109\117\115\116 \098\101 \097 \115\116\114\105\110\103 \111\114 \077\111\100\117\108\101\083\099\114\105\112\116\044 \103\111\116 \'\037\115\' \102\111\114 \'\037\115\'"):format(typeof(H),tostring(H)))end end function d._findModule(S,r,o)assert(typeof(r)=="\073\110\115\116\097\110\099\101","\066\097\100 \114\111\111\116")assert(type(o)=="\115\116\114\105\110\103","\066\097\100 \110\097\109\101")local d=S:_findPackageRoot(r)while d do local r=S:_getOrCreateLookup(d)if r[o]then return r[o]end local R=d:FindFirstChild(H.DEPENDENCY_FOLDER_NAME)if R then for r,H in pairs(R:GetChildren())do if H:IsA("\070\111\108\100\101\114")and H.Name:sub(1,1)=="\064"then for r,H in pairs(H:GetChildren())do local d=S:_getPackageFolderLookup(H)if d[o]then return d[o]end end else local r=S:_getPackageFolderLookup(H)if r[o]then return r[o]end end end end d=S:_findPackageRoot(d)end return nil end function d.GetLoader(H,r)assert(typeof(r)=="\073\110\115\116\097\110\099\101","\066\097\100 \109\111\100\117\108\101\083\099\114\105\112\116")return setmetatable({},{__call=function(o,S)return H:Require(r,S)end,__index=function(o,S)return H:Require(r,S)end})end function d._getPackageFolderLookup(H,r)if r:IsA("\079\098\106\101\099\116\086\097\108\117\101")then if r.Value then return H:_getOrCreateLookup(r.Value)else warn("\091\083\116\097\116\105\099\076\101\103\097\099\121\076\111\097\100\101\114\093 - \066\097\100 \108\105\110\107 \105\110 \112\097\099\107\097\103\101\070\111\108\100\101\114")return{}end elseif r:IsA("\070\111\108\100\101\114")or r:IsA("\067\097\109\101\114\097")then return H:_getOrCreateLookup(r)elseif r:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")then return H:_getOrCreateLookup(r)else warn(("\085\110\107\110\111\119\110 \105\110\115\116\097\110\099\101 \037\113 \040\037\115\041 \105\110 \100\101\112\101\110\100\101\110\099\121\070\111\108\100\101\114 - \037\113"):format(r.Name,r.ClassName,r:GetFullName()))return{}end end function d._getOrCreateLookup(H,r)assert(typeof(r)=="\073\110\115\116\097\110\099\101","\066\097\100 \112\097\099\107\097\103\101\070\111\108\100\101\114\079\114\077\111\100\117\108\101\083\099\114\105\112\116")if H._packageLookups[r]then return H._packageLookups[r]end local o={}H:_buildLookup(o,r)H._packageLookups[r]=o return o end function d._buildLookup(S,r,o)if o:IsA("\070\111\108\100\101\114")or o:IsA("\067\097\109\101\114\097")then if o.Name~=H.DEPENDENCY_FOLDER_NAME then for H,o in pairs(o:GetChildren())do S:_buildLookup(r,o)end end elseif o:IsA("\077\111\100\117\108\101\083\099\114\105\112\116")then r[o.Name]=o end end function d._findPackageRoot(H,r)assert(typeof(r)=="\073\110\115\116\097\110\099\101","\066\097\100 \105\110\115\116\097\110\099\101")local S=r.Parent while S and S~=game do if o.isPackage(S)then return S elseif H:_couldBePackageRootTopLevel(S)then return S else S=S.Parent end end return nil end function d._couldBePackageRootTopLevel(H,r)for r,H in pairs(r:GetChildren())do if H:IsA("\070\111\108\100\101\114")and H.Name:sub(1,1)=="\064"then for r,H in pairs(H:GetChildren())do if o.isPackage(H)then return true end end end end return true end function d._ensureFakeLoader(o,H)assert(typeof(H)=="\073\110\115\116\097\110\099\101","\066\097\100 \109\111\100\117\108\101")local d=H.Parent if not d then warn("\091\083\116\097\116\105\099\076\101\103\097\099\121\076\111\097\100\101\114\093 - \078\111 \112\097\114\101\110\116")return end local R=Load and true or false local h=d:FindFirstChild("\108\111\097\100\101\114")if h then if S.isBounceTemplate(h)then h.Archivable=R end return end local U=S.create(r,"\108\111\097\100\101\114")U.Archivable=R U.Parent=d end return d
--[=[
	@private
	@class StaticLegacyLoader
]=]

local loader = script.Parent
local ScriptInfoUtils = require(script.Parent.ScriptInfoUtils)
local LoaderUtils = require(script.Parent.LoaderUtils)
local BounceTemplateUtils = require(script.Parent.BounceTemplateUtils)

local StaticLegacyLoader = {}
StaticLegacyLoader.ClassName = "StaticLegacyLoader"
StaticLegacyLoader.__index = StaticLegacyLoader

function StaticLegacyLoader.new()
	local self = setmetatable({
		_packageLookups = {},
	}, StaticLegacyLoader)

	return self
end

function StaticLegacyLoader:__call(value)
	return self:Require(value)
end

function StaticLegacyLoader:Lock()
	error("Cannot start loader while not running")
end

function StaticLegacyLoader:Require(root, value)
	if type(value) == "number" then
		return require(value)
	elseif type(value) == "string" then
		-- use very slow module recovery mechanism
		local module = self:_findModule(root, value)
		if module then
			self:_ensureFakeLoader(module)
			return require(module)
		else
			error("Error: Library '" .. tostring(value) .. "' does not exist.", 2)
		end
	elseif typeof(value) == "Instance" and value:IsA("ModuleScript") then
		return require(value)
	else
		error(
			("Error: module must be a string or ModuleScript, got '%s' for '%s'"):format(typeof(value), tostring(value))
		)
	end
end

function StaticLegacyLoader:_findModule(root, name)
	assert(typeof(root) == "Instance", "Bad root")
	assert(type(name) == "string", "Bad name")

	-- Implement the node_modules recursive find algorithm
	local packageRoot = self:_findPackageRoot(root)
	while packageRoot do
		-- Build lookup
		local highLevelLookup = self:_getOrCreateLookup(packageRoot)
		if highLevelLookup[name] then
			return highLevelLookup[name]
		end

		-- Ok, search our package dependencies
		local dependencies = packageRoot:FindFirstChild(ScriptInfoUtils.DEPENDENCY_FOLDER_NAME)
		if dependencies then
			for _, instance in pairs(dependencies:GetChildren()) do
				if instance:IsA("Folder") and instance.Name:sub(1, 1) == "@" then
					for _, child in pairs(instance:GetChildren()) do
						local lookup = self:_getPackageFolderLookup(child)
						if lookup[name] then
							return lookup[name]
						end
					end
				else
					local lookup = self:_getPackageFolderLookup(instance)
					if lookup[name] then
						return lookup[name]
					end
				end
			end
		end

		-- We failed to find anything... search up a level...
		packageRoot = self:_findPackageRoot(packageRoot)
	end

	return nil
end

function StaticLegacyLoader:GetLoader(moduleScript)
	assert(typeof(moduleScript) == "Instance", "Bad moduleScript")

	return setmetatable({}, {
		__call = function(_self, value)
			return self:Require(moduleScript, value)
		end,
		__index = function(_self, key)
			return self:Require(moduleScript, key)
		end,
	})
end

function StaticLegacyLoader:_getPackageFolderLookup(instance)
	if instance:IsA("ObjectValue") then
		if instance.Value then
			return self:_getOrCreateLookup(instance.Value)
		else
			warn("[StaticLegacyLoader] - Bad link in packageFolder")
			return {}
		end
	elseif instance:IsA("Folder") or instance:IsA("Camera") then
		return self:_getOrCreateLookup(instance)
	elseif instance:IsA("ModuleScript") then
		return self:_getOrCreateLookup(instance)
	else
		warn(
			("Unknown instance %q (%s) in dependencyFolder - %q"):format(
				instance.Name,
				instance.ClassName,
				instance:GetFullName()
			)
		)
		return {}
	end
end

function StaticLegacyLoader:_getOrCreateLookup(packageFolderOrModuleScript)
	assert(typeof(packageFolderOrModuleScript) == "Instance", "Bad packageFolderOrModuleScript")

	if self._packageLookups[packageFolderOrModuleScript] then
		return self._packageLookups[packageFolderOrModuleScript]
	end

	local lookup = {}

	self:_buildLookup(lookup, packageFolderOrModuleScript)

	self._packageLookups[packageFolderOrModuleScript] = lookup
	return lookup
end

function StaticLegacyLoader:_buildLookup(lookup, instance)
	if instance:IsA("Folder") or instance:IsA("Camera") then
		if instance.Name ~= ScriptInfoUtils.DEPENDENCY_FOLDER_NAME then
			for _, item in pairs(instance:GetChildren()) do
				self:_buildLookup(lookup, item)
			end
		end
	elseif instance:IsA("ModuleScript") then
		lookup[instance.Name] = instance
	end
end

function StaticLegacyLoader:_findPackageRoot(instance)
	assert(typeof(instance) == "Instance", "Bad instance")

	local current = instance.Parent

	while current and current ~= game do
		if LoaderUtils.isPackage(current) then
			return current
		elseif self:_couldBePackageRootTopLevel(current) then
			return current
		else
			current = current.Parent
		end
	end

	return nil
end

function StaticLegacyLoader:_couldBePackageRootTopLevel(current)
	for _, instance in pairs(current:GetChildren()) do
		if instance:IsA("Folder") and instance.Name:sub(1, 1) == "@" then
			for _, item in pairs(instance:GetChildren()) do
				if LoaderUtils.isPackage(item) then
					return true
				end
			end
		end
	end

	return true
end

function StaticLegacyLoader:_ensureFakeLoader(module)
	assert(typeof(module) == "Instance", "Bad module")

	local parent = module.Parent
	if not parent then
		warn("[StaticLegacyLoader] - No parent")
		return
	end

	-- NexusUnitTest
	-- luacheck: ignore
	-- selene: allow(undefined_variable)
	local shouldBeArchivable = Load and true or false

	-- Already have link
	local found = parent:FindFirstChild("loader")
	if found then
		if BounceTemplateUtils.isBounceTemplate(found) then
			found.Archivable = shouldBeArchivable
		end

		return
	end

	local link = BounceTemplateUtils.create(loader, "loader")
	link.Archivable = shouldBeArchivable
	link.Parent = parent
end

return StaticLegacyLoader
