119 lines
3.5 KiB
Lua
119 lines
3.5 KiB
Lua
|
|
-- 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
|