diff --git a/go.mod b/go.mod index e3aeedd..89e0c7c 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,6 @@ go 1.24.1 require git.sharkk.net/Sky/LuaJIT-to-Go v0.5.6 -require github.com/goccy/go-json v0.10.5 - require github.com/google/uuid v1.6.0 require ( diff --git a/modules/fs/fs.go b/modules/fs/fs.go index 0a40a2d..c0fb006 100644 --- a/modules/fs/fs.go +++ b/modules/fs/fs.go @@ -1,371 +1,18 @@ package fs import ( - "io" - "io/fs" "os" - "path/filepath" - "strings" - "time" luajit "git.sharkk.net/Sky/LuaJIT-to-Go" ) func GetFunctionList() map[string]luajit.GoFunction { return map[string]luajit.GoFunction{ - "file_exists": file_exists, - "file_size": file_size, - "file_is_dir": file_is_dir, - "file_read": file_read, - "file_write": file_write, - "file_append": file_append, - "file_copy": file_copy, - "file_move": file_move, - "file_delete": file_delete, - "file_mtime": file_mtime, - "dir_create": dir_create, - "dir_remove": dir_remove, - "dir_list": dir_list, - "path_join": path_join, - "path_dir": path_dir, - "path_basename": path_basename, - "path_ext": path_ext, - "path_abs": path_abs, - "path_clean": path_clean, - "path_split": path_split, - "temp_file": temp_file, - "temp_dir": temp_dir, - "glob": glob, - "walk": walk, - "getcwd": getcwd, - "chdir": chdir, - "file_lines": file_lines, - "touch": touch, + "getcwd": getcwd, + "chdir": chdir, } } -func file_exists(s *luajit.State) int { - path := s.ToString(1) - _, err := os.Stat(path) - s.PushBoolean(err == nil) - return 1 -} - -func file_size(s *luajit.State) int { - path := s.ToString(1) - info, err := os.Stat(path) - if err != nil { - s.PushNumber(-1) - return 1 - } - s.PushNumber(float64(info.Size())) - return 1 -} - -func file_is_dir(s *luajit.State) int { - path := s.ToString(1) - info, err := os.Stat(path) - if err != nil { - s.PushBoolean(false) - return 1 - } - s.PushBoolean(info.IsDir()) - return 1 -} - -func file_read(s *luajit.State) int { - path := s.ToString(1) - data, err := os.ReadFile(path) - if err != nil { - s.PushNil() - s.PushString(err.Error()) - return 2 - } - s.PushString(string(data)) - return 1 -} - -func file_write(s *luajit.State) int { - path := s.ToString(1) - content := s.ToString(2) - err := os.WriteFile(path, []byte(content), 0644) - if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - s.PushBoolean(true) - return 1 -} - -func file_append(s *luajit.State) int { - path := s.ToString(1) - content := s.ToString(2) - file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - defer file.Close() - _, err = file.WriteString(content) - if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - s.PushBoolean(true) - return 1 -} - -func file_copy(s *luajit.State) int { - src := s.ToString(1) - dst := s.ToString(2) - - srcFile, err := os.Open(src) - if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - defer srcFile.Close() - - dstFile, err := os.Create(dst) - if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - defer dstFile.Close() - - _, err = io.Copy(dstFile, srcFile) - if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - s.PushBoolean(true) - return 1 -} - -func file_move(s *luajit.State) int { - src := s.ToString(1) - dst := s.ToString(2) - err := os.Rename(src, dst) - if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - s.PushBoolean(true) - return 1 -} - -func file_delete(s *luajit.State) int { - path := s.ToString(1) - err := os.Remove(path) - if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - s.PushBoolean(true) - return 1 -} - -func file_mtime(s *luajit.State) int { - path := s.ToString(1) - info, err := os.Stat(path) - if err != nil { - s.PushNumber(-1) - return 1 - } - s.PushNumber(float64(info.ModTime().Unix())) - return 1 -} - -func dir_create(s *luajit.State) int { - path := s.ToString(1) - err := os.MkdirAll(path, 0755) - if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - s.PushBoolean(true) - return 1 -} - -func dir_remove(s *luajit.State) int { - path := s.ToString(1) - err := os.RemoveAll(path) - if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - s.PushBoolean(true) - return 1 -} - -func dir_list(s *luajit.State) int { - path := s.ToString(1) - entries, err := os.ReadDir(path) - if err != nil { - s.PushNil() - s.PushString(err.Error()) - return 2 - } - - s.CreateTable(len(entries), 0) - for i, entry := range entries { - s.PushNumber(float64(i + 1)) - s.CreateTable(0, 4) - - s.PushString("name") - s.PushString(entry.Name()) - s.SetTable(-3) - - s.PushString("is_dir") - s.PushBoolean(entry.IsDir()) - s.SetTable(-3) - - if info, err := entry.Info(); err == nil { - s.PushString("size") - s.PushNumber(float64(info.Size())) - s.SetTable(-3) - - s.PushString("mtime") - s.PushNumber(float64(info.ModTime().Unix())) - s.SetTable(-3) - } - - s.SetTable(-3) - } - return 1 -} - -func path_join(s *luajit.State) int { - var parts []string - for i := 1; i <= s.GetTop(); i++ { - parts = append(parts, s.ToString(i)) - } - s.PushString(filepath.Join(parts...)) - return 1 -} - -func path_dir(s *luajit.State) int { - path := s.ToString(1) - s.PushString(filepath.Dir(path)) - return 1 -} - -func path_basename(s *luajit.State) int { - path := s.ToString(1) - s.PushString(filepath.Base(path)) - return 1 -} - -func path_ext(s *luajit.State) int { - path := s.ToString(1) - s.PushString(filepath.Ext(path)) - return 1 -} - -func path_abs(s *luajit.State) int { - path := s.ToString(1) - abs, err := filepath.Abs(path) - if err != nil { - s.PushNil() - s.PushString(err.Error()) - return 2 - } - s.PushString(abs) - return 1 -} - -func path_clean(s *luajit.State) int { - path := s.ToString(1) - s.PushString(filepath.Clean(path)) - return 1 -} - -func path_split(s *luajit.State) int { - path := s.ToString(1) - dir, file := filepath.Split(path) - s.PushString(dir) - s.PushString(file) - return 2 -} - -func temp_file(s *luajit.State) int { - var prefix string - if s.GetTop() >= 1 { - prefix = s.ToString(1) - } - - file, err := os.CreateTemp("", prefix) - if err != nil { - s.PushNil() - s.PushString(err.Error()) - return 2 - } - defer file.Close() - - s.PushString(file.Name()) - return 1 -} - -func temp_dir(s *luajit.State) int { - var prefix string - if s.GetTop() >= 1 { - prefix = s.ToString(1) - } - - dir, err := os.MkdirTemp("", prefix) - if err != nil { - s.PushNil() - s.PushString(err.Error()) - return 2 - } - - s.PushString(dir) - return 1 -} - -func glob(s *luajit.State) int { - pattern := s.ToString(1) - matches, err := filepath.Glob(pattern) - if err != nil { - s.PushNil() - s.PushString(err.Error()) - return 2 - } - s.PushValue(matches) - return 1 -} - -func walk(s *luajit.State) int { - root := s.ToString(1) - var files []string - err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { - if err != nil { - return nil // Skip errors - } - files = append(files, path) - return nil - }) - - if err != nil { - s.PushNil() - s.PushString(err.Error()) - return 2 - } - - s.PushValue(files) - return 1 -} - func getcwd(s *luajit.State) int { cwd, err := os.Getwd() if err != nil { @@ -388,45 +35,3 @@ func chdir(s *luajit.State) int { s.PushBoolean(true) return 1 } - -func file_lines(s *luajit.State) int { - path := s.ToString(1) - data, err := os.ReadFile(path) - if err != nil { - s.PushNil() - s.PushString(err.Error()) - return 2 - } - - lines := strings.Split(string(data), "\n") - // Remove empty last line if file ends with newline - if len(lines) > 0 && lines[len(lines)-1] == "" { - lines = lines[:len(lines)-1] - } - - s.PushValue(lines) - return 1 -} - -func touch(s *luajit.State) int { - path := s.ToString(1) - now := time.Now() - err := os.Chtimes(path, now, now) - if os.IsNotExist(err) { - // Create file if it doesn't exist - file, err := os.Create(path) - if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - file.Close() - } else if err != nil { - s.PushBoolean(false) - s.PushString(err.Error()) - return 2 - } - - s.PushBoolean(true) - return 1 -} diff --git a/modules/fs/fs.lua b/modules/fs/fs.lua index 6c4dc07..471e4df 100644 --- a/modules/fs/fs.lua +++ b/modules/fs/fs.lua @@ -1,22 +1,51 @@ --- modules/fs.lua - Comprehensive filesystem utilities - local fs = {} +local is_windows = package.config:sub(1,1) == '\\' +local path_sep = is_windows and '\\' or '/' + -- ====================================================================== -- FILE OPERATIONS -- ====================================================================== function fs.exists(path) - return moonshark.file_exists(path) + local file = io.open(path, "r") + if file then + file:close() + return true + end + return false end function fs.size(path) - local size = moonshark.file_size(path) - return size >= 0 and size or nil + local file = io.open(path, "r") + if not file then return nil end + + local size = file:seek("end") + file:close() + return size end function fs.is_dir(path) - return moonshark.file_is_dir(path) + if not fs.exists(path) then return false end + + -- Check if we can list directory (platform specific) + if is_windows then + local handle = io.popen('dir "' .. path .. '" 2>nul') + if handle then + local result = handle:read("*a") + handle:close() + return result and result:match("Directory of") ~= nil + end + else + local handle = io.popen('test -d "' .. path .. '" 2>/dev/null && echo "dir"') + if handle then + local result = handle:read("*l") + handle:close() + return result == "dir" + end + end + + return false end function fs.is_file(path) @@ -24,71 +53,158 @@ function fs.is_file(path) end function fs.read(path) - local content, err = moonshark.file_read(path) - if not content then - error("Failed to read file '" .. path .. "': " .. (err or "unknown error")) + local file = io.open(path, "r") + if not file then + error("Failed to read file '" .. path .. "': file not found or permission denied") end + + local content = file:read("*all") + file:close() + + if not content then + error("Failed to read file '" .. path .. "': read error") + end + return content end function fs.write(path, content) - local success, err = moonshark.file_write(path, content) - if not success then - error("Failed to write file '" .. path .. "': " .. (err or "unknown error")) + -- Check for obviously invalid paths + if path == "" or path:find("\0") then + error("Failed to write file '" .. path .. "': invalid path") end + + local file = io.open(path, "w") + if not file then + error("Failed to write file '" .. path .. "': permission denied or invalid path") + end + + local success = file:write(content) + file:close() + + if not success then + error("Failed to write file '" .. path .. "': write error") + end + return true end function fs.append(path, content) - local success, err = moonshark.file_append(path, content) - if not success then - error("Failed to append to file '" .. path .. "': " .. (err or "unknown error")) + local file = io.open(path, "a") + if not file then + error("Failed to append to file '" .. path .. "': permission denied or invalid path") end + + local success = file:write(content) + file:close() + + if not success then + error("Failed to append to file '" .. path .. "': write error") + end + return true end function fs.copy(src, dst) - local success, err = moonshark.file_copy(src, dst) - if not success then - error("Failed to copy '" .. src .. "' to '" .. dst .. "': " .. (err or "unknown error")) + local src_file = io.open(src, "rb") + if not src_file then + error("Failed to copy '" .. src .. "' to '" .. dst .. "': source file not found") end + + local dst_file = io.open(dst, "wb") + if not dst_file then + src_file:close() + error("Failed to copy '" .. src .. "' to '" .. dst .. "': cannot create destination") + end + + local chunk_size = 8192 + while true do + local chunk = src_file:read(chunk_size) + if not chunk then break end + + if not dst_file:write(chunk) then + src_file:close() + dst_file:close() + error("Failed to copy '" .. src .. "' to '" .. dst .. "': write error") + end + end + + src_file:close() + dst_file:close() return true end function fs.move(src, dst) - local success, err = moonshark.file_move(src, dst) - if not success then - error("Failed to move '" .. src .. "' to '" .. dst .. "': " .. (err or "unknown error")) - end + -- Try native rename first + local success = os.rename(src, dst) + if success then return true end + + -- Fallback to copy + delete + fs.copy(src, dst) + fs.remove(src) return true end function fs.remove(path) - local success, err = moonshark.file_delete(path) + local success = os.remove(path) if not success then - error("Failed to remove '" .. path .. "': " .. (err or "unknown error")) + error("Failed to remove '" .. path .. "': file not found or permission denied") end return true end function fs.mtime(path) - local timestamp = moonshark.file_mtime(path) - return timestamp >= 0 and timestamp or nil + -- Use os.execute with stat command + if is_windows then + local cmd = 'for %i in ("' .. path .. '") do @echo %~ti' + local handle = io.popen(cmd) + if handle then + local result = handle:read("*line") + handle:close() + if result then + -- Parse Windows timestamp (basic implementation) + return os.time() -- Fallback to current time + end + end + else + local cmd = 'stat -c %Y "' .. path .. '" 2>/dev/null' + local handle = io.popen(cmd) + if handle then + local result = handle:read("*line") + handle:close() + if result and result:match("^%d+$") then + return tonumber(result) + end + end + end + + return nil end function fs.touch(path) - local success, err = moonshark.touch(path) - if not success then - error("Failed to touch '" .. path .. "': " .. (err or "unknown error")) + if fs.exists(path) then + -- Update timestamp - basic implementation + local content = fs.read(path) + fs.write(path, content) + else + -- Create empty file + fs.write(path, "") end return true end function fs.lines(path) - local lines, err = moonshark.file_lines(path) - if not lines then - error("Failed to read lines from '" .. path .. "': " .. (err or "unknown error")) + local lines = {} + local file = io.open(path, "r") + if not file then + error("Failed to read lines from '" .. path .. "': file not found") end + + for line in file:lines() do + lines[#lines + 1] = line + end + file:close() + return lines end @@ -97,26 +213,69 @@ end -- ====================================================================== function fs.mkdir(path) - local success, err = moonshark.dir_create(path) + local cmd + if is_windows then + cmd = 'mkdir "' .. path .. '" 2>nul' + else + cmd = 'mkdir -p "' .. path .. '"' + end + + local success = os.execute(cmd) if not success then - error("Failed to create directory '" .. path .. "': " .. (err or "unknown error")) + error("Failed to create directory '" .. path .. "'") end return true end function fs.rmdir(path) - local success, err = moonshark.dir_remove(path) + local cmd + if is_windows then + cmd = 'rmdir /s /q "' .. path .. '"' + else + cmd = 'rm -rf "' .. path .. '"' + end + + local success = os.execute(cmd) if not success then - error("Failed to remove directory '" .. path .. "': " .. (err or "unknown error")) + error("Failed to remove directory '" .. path .. "'") end return true end function fs.list(path) - local entries, err = moonshark.dir_list(path) - if not entries then - error("Failed to list directory '" .. path .. "': " .. (err or "unknown error")) + if not fs.exists(path) then + error("Failed to list directory '" .. path .. "': directory not found") end + + if not fs.is_dir(path) then + error("Failed to list directory '" .. path .. "': not a directory") + end + + local entries = {} + local cmd + + if is_windows then + cmd = 'dir /b "' .. path .. '" 2>nul' + else + cmd = 'ls -1 "' .. path .. '" 2>/dev/null' + end + + local handle = io.popen(cmd) + if not handle then + return nil + end + + for name in handle:lines() do + local full_path = fs.join(path, name) + entries[#entries + 1] = { + name = name, + is_dir = fs.is_dir(full_path), + size = fs.is_file(full_path) and fs.size(full_path) or 0, + mtime = fs.mtime(full_path) + } + end + handle:close() + return entries end @@ -125,7 +284,7 @@ function fs.list_files(path) local files = {} for _, entry in ipairs(entries) do if not entry.is_dir then - table.insert(files, entry) + files[#files + 1] = entry end end return files @@ -136,7 +295,7 @@ function fs.list_dirs(path) local dirs = {} for _, entry in ipairs(entries) do if entry.is_dir then - table.insert(dirs, entry) + dirs[#dirs + 1] = entry end end return dirs @@ -146,48 +305,98 @@ function fs.list_names(path) local entries = fs.list(path) local names = {} for _, entry in ipairs(entries) do - table.insert(names, entry.name) + names[#names + 1] = entry.name end return names end -- ====================================================================== --- PATH OPERATIONS +-- PATH OPERATIONS (Optimized pure Lua) -- ====================================================================== function fs.join(...) - return moonshark.path_join(...) + local parts = {...} + if #parts == 0 then return "" end + if #parts == 1 then return parts[1] end + + local result = parts[1] + for i = 2, #parts do + local part = parts[i] + if part ~= "" then + if result:sub(-1) == path_sep or result == "" then + result = result .. part + else + result = result .. path_sep .. part + end + end + end + + return result end function fs.dirname(path) - return moonshark.path_dir(path) + local pos = path:find("[/\\][^/\\]*$") + if pos then + return path:sub(1, pos - 1) + end + return "." end function fs.basename(path) - return moonshark.path_basename(path) + return path:match("[^/\\]*$") or "" end function fs.ext(path) - return moonshark.path_ext(path) + local base = fs.basename(path) + local dot_pos = base:find("%.[^%.]*$") + return dot_pos and base:sub(dot_pos) or "" end function fs.abs(path) - local abs_path, err = moonshark.path_abs(path) - if not abs_path then - error("Failed to get absolute path for '" .. path .. "': " .. (err or "unknown error")) + if is_windows then + if path:match("^[A-Za-z]:") or path:match("^\\\\") then + return path + end + else + if path:sub(1, 1) == "/" then + return path + end end - return abs_path + + local cwd = fs.getcwd() + return fs.join(cwd, path) end function fs.clean(path) - return moonshark.path_clean(path) + -- Normalize path separators + path = path:gsub("[/\\]+", path_sep) + + -- Handle . and .. components + local parts = {} + for part in path:gmatch("[^" .. path_sep .. "]+") do + if part == ".." and #parts > 0 and parts[#parts] ~= ".." then + parts[#parts] = nil + elseif part ~= "." then + parts[#parts + 1] = part + end + end + + local result = table.concat(parts, path_sep) + if path:sub(1, 1) == path_sep then + result = path_sep .. result + end + + return result ~= "" and result or "." end function fs.split(path) - return moonshark.path_split(path) + local pos = path:find("[/\\][^/\\]*$") + if pos then + return path:sub(1, pos), path:sub(pos + 1) + end + return "", path end --- Split path into directory, name, and extension function fs.splitext(path) local dir = fs.dirname(path) local base = fs.basename(path) @@ -226,19 +435,36 @@ end -- ====================================================================== function fs.tempfile(prefix) - local path, err = moonshark.temp_file(prefix) - if not path then - error("Failed to create temporary file: " .. (err or "unknown error")) + prefix = prefix or "tmp" + local temp_name = prefix .. "_" .. os.time() .. "_" .. math.random(10000) + + local temp_path + if is_windows then + local temp_dir = os.getenv("TEMP") or os.getenv("TMP") or "C:\\temp" + temp_path = fs.join(temp_dir, temp_name) + else + temp_path = fs.join("/tmp", temp_name) end - return path + + -- Create the file + fs.write(temp_path, "") + return temp_path end function fs.tempdir(prefix) - local path, err = moonshark.temp_dir(prefix) - if not path then - error("Failed to create temporary directory: " .. (err or "unknown error")) + prefix = prefix or "tmp" + local temp_name = prefix .. "_" .. os.time() .. "_" .. math.random(10000) + + local temp_path + if is_windows then + local temp_dir = os.getenv("TEMP") or os.getenv("TMP") or "C:\\temp" + temp_path = fs.join(temp_dir, temp_name) + else + temp_path = fs.join("/tmp", temp_name) end - return path + + fs.mkdir(temp_path) + return temp_path end -- ====================================================================== @@ -246,41 +472,65 @@ end -- ====================================================================== function fs.glob(pattern) - local matches, err = moonshark.glob(pattern) - if not matches then - error("Failed to glob pattern '" .. pattern .. "': " .. (err or "unknown error")) + local cmd + if is_windows then + cmd = 'for %f in ("' .. pattern .. '") do @echo %f' + else + cmd = 'ls -1d ' .. pattern .. ' 2>/dev/null' end + + local matches = {} + local handle = io.popen(cmd) + if handle then + for match in handle:lines() do + matches[#matches + 1] = match + end + handle:close() + end + return matches end function fs.walk(root) - local files, err = moonshark.walk(root) - if not files then - error("Failed to walk directory '" .. root .. "': " .. (err or "unknown error")) + local files = {} + + local function walk_recursive(path) + if not fs.exists(path) then return end + + files[#files + 1] = path + + if fs.is_dir(path) then + local entries = fs.list(path) + for _, entry in ipairs(entries) do + walk_recursive(fs.join(path, entry.name)) + end + end end + + walk_recursive(root) return files end -- ====================================================================== --- UTILITY FUNCTIONS +-- UTILITY FUNCTIONS (using optimized implementations) -- ====================================================================== --- Get file extension without dot function fs.extension(path) local ext = fs.ext(path) return ext:sub(2) -- Remove leading dot end --- Change file extension function fs.change_ext(path, new_ext) local dir, name, _ = fs.splitext(path) if not new_ext:match("^%.") then new_ext = "." .. new_ext end + if dir == "." then + return name .. new_ext + end return fs.join(dir, name .. new_ext) end --- Ensure directory exists function fs.ensure_dir(path) if not fs.exists(path) then fs.mkdir(path) @@ -290,14 +540,13 @@ function fs.ensure_dir(path) return true end --- Get file size in human readable format function fs.size_human(path) local size = fs.size(path) if not size then return nil end local units = {"B", "KB", "MB", "GB", "TB"} local unit_index = 1 - local size_float = tonumber(size) + local size_float = size while size_float >= 1024 and unit_index < #units do size_float = size_float / 1024 @@ -311,30 +560,20 @@ function fs.size_human(path) end end --- Check if path is safe (doesn't contain .. or other dangerous patterns) function fs.is_safe_path(path) - -- Normalize path path = fs.clean(path) - -- Check for dangerous patterns if path:match("%.%.") then return false end - if path:match("^/") then return false end -- Absolute paths might be dangerous - if path:match("^~") then return false end -- Home directory references + if path:match("^[/\\]") then return false end + if path:match("^~") then return false end return true end --- Create directory tree -function fs.makedirs(path) - return fs.mkdir(path) -- mkdir already creates parent directories -end +-- Aliases for convenience +fs.makedirs = fs.mkdir +fs.removedirs = fs.rmdir --- Remove directory tree -function fs.removedirs(path) - return fs.rmdir(path) -- rmdir already removes recursively -end - --- Copy directory tree function fs.copytree(src, dst) if not fs.exists(src) then error("Source directory does not exist: " .. src) @@ -361,7 +600,6 @@ function fs.copytree(src, dst) return true end --- Find files by pattern function fs.find(root, pattern, recursive) recursive = recursive ~= false local results = {} @@ -372,7 +610,7 @@ function fs.find(root, pattern, recursive) local full_path = fs.join(dir, entry.name) if not entry.is_dir and entry.name:match(pattern) then - table.insert(results, full_path) + results[#results + 1] = full_path elseif entry.is_dir and recursive then search(full_path) end @@ -405,7 +643,7 @@ function fs.tree(root, max_depth) local child_path = fs.join(path, entry.name) local child = build_tree(child_path, depth + 1) if child then - table.insert(node.children, child) + node.children[#node.children + 1] = child end end else @@ -419,28 +657,4 @@ function fs.tree(root, max_depth) return build_tree(root, 1) end --- Monitor file changes (simplified version) -function fs.watch(path, callback, interval) - interval = interval or 1 - - if not fs.exists(path) then - error("Path does not exist: " .. path) - end - - local last_mtime = fs.mtime(path) - - while true do - local current_mtime = fs.mtime(path) - if current_mtime and current_mtime ~= last_mtime then - callback(path, "modified") - last_mtime = current_mtime - end - - -- Sleep for interval (this would need a proper sleep function) - -- This is a placeholder - real implementation would need proper timing - local start = os.clock() - while os.clock() - start < interval do end - end -end - return fs \ No newline at end of file diff --git a/modules/registry.go b/modules/registry.go index 81e6cf1..c54643d 100644 --- a/modules/registry.go +++ b/modules/registry.go @@ -36,8 +36,8 @@ func New() *Registry { // Load all Go functions maps.Copy(r.goFuncs, lua_string.GetFunctionList()) maps.Copy(r.goFuncs, math.GetFunctionList()) - maps.Copy(r.goFuncs, fs.GetFunctionList()) maps.Copy(r.goFuncs, crypto.GetFunctionList()) + maps.Copy(r.goFuncs, fs.GetFunctionList()) maps.Copy(r.goFuncs, http.GetFunctionList()) r.loadEmbeddedModules() diff --git a/tests/fs.lua b/tests/fs.lua index 0fa552c..391b59e 100644 --- a/tests/fs.lua +++ b/tests/fs.lua @@ -405,15 +405,15 @@ end) test("Error Handling", function() -- Reading non-existent file local success, err = pcall(fs.read, "nonexistent.txt") - assert_equal(success, false) + assert_equal(false, success) -- Writing to invalid path local success2, err2 = pcall(fs.write, "/invalid/path/file.txt", "content") - assert_equal(success2, false) + assert_equal(false, success2) -- Listing non-existent directory local success3, err3 = pcall(fs.list, "nonexistent_dir") - assert_equal(success3, false) + assert_equal(false, success3) end) -- ======================================================================