Skip to content

Commit

Permalink
fix: pathRegexp() returns incorrect pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
AMD-NICK committed Sep 6, 2024
1 parent b983a2d commit 97656d1
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 52 deletions.
18 changes: 18 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug!",
"type": "lua",
"request": "launch",
"stopOnEntry": true,
// "runtimeExecutable": "/usr/bin/lua",
// "runtimeArgs": "${workspaceFolder}/init.lua",
// "runtimeArgs": "${file}",
// "program": "${file}",
"program": "examples/downloads/init.lua",
"cwd": "${fileWorkspaceFolder}"
// "luaVersion": "luajit",
}
]
}
10 changes: 10 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "echo var",
"type": "shell",
"command": "echo ${fileWorkspaceFolder}"
}
]
}
92 changes: 40 additions & 52 deletions lua/express/utils.lua
Original file line number Diff line number Diff line change
@@ -1,69 +1,41 @@
local pattern_escape_replacements = {
["("] = "%(",
[")"] = "%)",
["."] = "%.",
["%"] = "%%",
["+"] = "%+",
["-"] = "%-",
-- ["*"] = "%*",
["?"] = "%?",
["["] = "%[",
["]"] = "%]",
["^"] = "%^",
["$"] = "%$",
["\0"] = "%z"
}

local pattern_safe = function( str )
return ( string.gsub( str, ".", pattern_escape_replacements ) )
end

-- https://github.com/pillarjs/path-to-regexp
local function pathRegexp(path, strict, ending)
-- В финальную регулярку не передаются параметры ?a=b&c=d
-- Для /files/:file(*) возвращается /^\/files\/(?:((.*)))\/?$/i
-- Для /files/:file* возвращается /^\/files\/(?:([^\/]+?)((?:[\/].+?)?))\/?$/i
-- Заметки (второе без (*) в конце пути):
-- /users/:id/some/:action(*)
-- /^\/users\/(?:([^\/]+?))\/some\/(?:((.*)))\/?$/i
-- /^\/users\/(?:([^\/]+?))\/some\/(?:([^\/]+?))\/?$/i
local function regexpFromPath(path, strict, ending)
local keys = {}

-- Удаляем символ / в начале, если strict не установлен
if not strict then path = path:gsub("^/", "") end

path = pattern_safe(path)

-- path = path:gsub("%.", "%%.") -- заменяем точку на %.
-- path = path:gsub("%-", "%%-")
-- #todo "^ $ ( ) % . [ ] * + - ?", https://github.com/Facepunch/garrysmod/blob/e189f14c088298ca800136fcfcfaf5d8535b6648/garrysmod/lua/includes/extensions/string.lua#L58-L76
-- только учесть, что "*" должна поддерживаться
-- path = pattern_safe(path) -- не знаю зачем добавлял. Больше мешало, чем помогало
-- учесть, что "*" должна поддерживаться

-- Заменяем :param на соответствующий паттерн
path = path:gsub("(/?)%:([^/]+)", function(slash, key)
keys[#keys + 1] = key
-- Генерируем паттерн для параметра
return slash .. "([^/]+)"
local gsubed, changes = key:gsub("%(%*%)$", "")
keys[#keys + 1] = gsubed
return slash .. (changes > 0 and "(.*)" or "([^/]+)")
end)

path = path .. (strict and "/" or "/?")

-- /test/:foo/:bar создаст ^/test/([^/]+)/([^/]+)/?$
-- в итоге match вернет параметры вместо пути, а нужен сам путь
-- PRINT{ string.match("123", "((1)(2(3)))") } -- 123 1 23 3 (общая группа, вторая, третья, ...)
if #keys > 0 then
path = "(/" .. path .. "/?)"
else
path = "/" .. path .. "/?"
end


-- Экранируем символы, которые могут быть интерпретированы как регулярные выражения
-- path = path:gsub("([%(%)%.%[%]%*%+%-%?%^%$%%])", "%%%1")
-- path = path:gsub('([/%.])', '\\%1')
if #keys > 0 then path = "(" .. path .. ")" end

-- Добавляем начало и, если нужно, конец регулярного выражения
path = "^" .. path .. (ending and "$" or "")
path = path:gsub("%*", "(.*)")

-- Возвращаем регулярное выражение
return path, keys
end

-- local pattern, keys = pathRegexp("/users/:id/:action*", false, true)
-- PRINT({pattern = pattern, keys = keys}) -- Выведет "^/users/([%w_]+)/([%w_]+)(.*)$"
-- PRINT(string.match("/users/123/create?foo=bar", pattern)) -- "123", "create", "?foo=bar"
-- local pattern, keys = regexpFromPath("/users/:id/some/:action(*)", false, true)
-- require("tlib").PRINT({pattern = pattern, keys = keys}) -- ^(/users/([^/]+)/some/(.*)/?)$
-- require("tlib").PRINT(string.match("/users/123/some/create?foo=bar", pattern)) -- $full_path, "123", "create?foo=bar"
-- require("tlib").PRINT(string.match("/users/123/some/create/post?foo=bar", pattern)) -- $full_path, "123", "create/post?foo=bar"

local function getPathname(full_path)
if full_path == "/" then return "/" end
Expand Down Expand Up @@ -116,10 +88,26 @@ local function string_URLDecode(str)
end)
end

local function string_Split(str, char)
local t = {}
for s in string.gmatch(str, "([^" .. char .. "]+)") do
t[#t + 1] = s
end
return t
end

-- https://github.com/expressjs/express/blob/2a980ad16052e53b398c9953fea50e3daa0b495c/lib/utils.js#L56
-- Только для res:sendFile сейчас. #todo поддержка windows (не сложно), а с ней path.lua тоже под Windows сделать
local function isAbsolute(path)
return path:sub(1, 1) == "/"
end

-- require("express.utils").urldecode
return {
pathRegexp = pathRegexp,
getPathname = getPathname,
debugPrint = debugPrint,
urldecode = string_URLDecode,
pathRegexp = regexpFromPath,
getPathname = getPathname,
debugPrint = debugPrint,
urldecode = string_URLDecode,
isAbsolute = isAbsolute,
string_split = string_Split
}

0 comments on commit 97656d1

Please sign in to comment.