-- this is a lua adaptation of Godot's URI.gd -- https://gist.github.com/coderofsalvation/b2b111a2631fbdc8e76d6cab3bea8f17 local url = {} -- Helper function to split a string by a delimiter local function split(str, delimiter) local result = {} if delimiter == "" then return {str} end local pattern = string.format("([^%s]+)", delimiter) for match in string.gmatch(str, pattern) do table.insert(result, match) end return result end -- Helper for guess_type (converts numbers/booleans from strings) local function guess_type(val) if tonumber(val) then return tonumber(val) end if val == "true" then return true end if val == "false" then return false end return val end -- Helper to parse query parameters and fragments local function parseArgs(fragment) local ARG = {} if not fragment or fragment == "" then return ARG end local items = split(fragment, "&") for _, item in ipairs(items) do local key_value = split(item, "=") if #key_value > 1 then ARG[key_value[1]] = guess_type(key_value[2]) elseif #key_value == 1 then ARG[key_value[1]] = "" end end return ARG end -- Main URL Parser function attached to the module object function url.parse(url_string) -- Setup initial URI table structure local URI = { domain = "", fragment = {}, file = "", extension = "", string = url_string, protocol = "", path = "", query = {}, hash = "", URN = "", isLocal = false } local remaining = url_string local protocol = string.match(remaining, "^(%w+://)") -- protocol if protocol then URI.protocol = protocol:gsub("://", "") remaining = remaining:sub(#protocol + 1) end local hash = string.match(remaining, "(#.*)$") -- fragment if hash then URI.hash = hash remaining = remaining:sub(1, #remaining - #hash) end local query = string.match(remaining, "(%?[^#]+)$") if query then URI.query = query remaining = remaining:sub(1, #remaining - #query) end URI.path = remaining -- Process Path, Domain, and File if URI.path and URI.path ~= "" then local pathParts = split(URI.path, "/") if #pathParts > 1 then local firstPart = pathParts[1] -- Check if the first part looks like a domain (contains '.' or ':') if string.find(firstPart, "%.") or string.find(firstPart, ":") then URI.domain = table.remove(pathParts, 1) end end -- Reconstruct path URI.path = table.concat(pathParts, "/") -- Extract file if present if #pathParts > 0 then local lastPart = pathParts[#pathParts] if string.find(lastPart, "%.") then URI.file = lastPart URI.extension = URI.file:match("%.([^%.]+)$"):upper() end end end if URI.hash and URI.hash ~= "" then URI.fragment = parseArgs(URI.hash:sub(2)) -- sub(2) skips the '#' else URI.fragment = {} end if URI.query and type(URI.query) == "string" and URI.query ~= "" then URI.query = parseArgs(URI.query:sub(2)) -- sub(2) skips the '?' else URI.query = {} end if URI.domain ~= "" then URI.URN = URI.string:gsub("%?.*", "") else URI.URN = "" end URI.isLocal = (URI.domain == "") return URI end -- Return the module table so it can be assigned via require() return url