-- Core utility functions local M = {} -- Import submodules local logging = require('notex.utils.logging') local errors = require('notex.utils.errors') local types = require('notex.utils.types') local validation = require('notex.utils.validation') local date_utils = require('notex.utils.date') local cache = require('notex.utils.cache') -- Generate unique ID function M.generate_id() local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' return string.gsub(template, '[xy]', function(c) local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb) return string.format('%x', v) end) end -- Generate SHA256 hash function M.sha256(data) local cmd = string.format("echo '%s' | sha256sum | cut -d' ' -f1", data) local handle = io.popen(cmd) if not handle then return nil end local result = handle:read("*a") handle:close() return result:gsub("%s+", "") end -- Deep merge tables function M.deep_merge(target, source) for key, value in pairs(source) do if type(value) == 'table' and type(target[key]) == 'table' then M.deep_merge(target[key], value) else target[key] = value end end return target end -- Check if file exists function M.file_exists(path) local f = io.open(path, "r") if f then f:close() return true end return false end -- Read file content function M.read_file(path) local file = io.open(path, "r") if not file then return nil, "Cannot open file: " .. path end local content = file:read("*a") file:close() return content end -- Write file content function M.write_file(path, content) local file = io.open(path, "w") if not file then return false, "Cannot write to file: " .. path end file:write(content) file:close() return true end -- Get file modification time function M.get_file_mtime(path) local handle = io.popen("stat -c %Y " .. path .. " 2>/dev/null") if not handle then return nil end local result = handle:read("*a") handle:close() local mtime = tonumber(result:gsub("%s+", "")) return mtime end -- Validate file encoding (UTF-8 check) function M.is_utf8(path) local file = io.open(path, "rb") if not file then return false end local content = file:read("*a") file:close() -- Simple UTF-8 validation local valid, pos = utf8.len(content) return valid ~= nil end -- Format error message function M.format_error(error_type, message, context) local error_obj = { error_type = error_type, message = message, timestamp = os.time() } if context then error_obj.context = context end return error_obj end -- Forward logging functions to centralized logging M.trace = logging.trace M.debug = logging.debug M.info = logging.info M.warn = logging.warn M.error = logging.error M.fatal = logging.fatal M.log = logging.log M.timer = logging.timer -- Forward error handling functions M.handle_error = errors.handle_error M.safe_execute = errors.safe_execute M.wrap = errors.wrap M.create_error = errors.create_error -- Forward type utilities M.detect_type = types.detect_type M.convert_to_type = types.convert_to_type M.infer_schema = types.infer_schema -- Forward validation utilities M.validate_value = validation.validate_value M.validate_document_properties = validation.validate_document_properties M.sanitize_input = validation.sanitize_input -- Forward date utilities M.parse_date = date_utils.parse_date M.format_date = date_utils.format_date M.get_relative_time = date_utils.get_relative_time -- Forward cache utilities M.cache_set = cache.set M.cache_get = cache.get M.cache_get_or_set = cache.get_or_set M.cache_invalidate = cache.invalidate M.cache_clear_all = cache.clear_all M.cache_get_stats = cache.get_stats M.cache_init = cache.init -- Simple timer for backward compatibility function M.simple_timer(name) local start_time = vim.loop.hrtime() return function() local end_time = vim.loop.hrtime() local elapsed_ms = (end_time - start_time) / 1e6 M.log("INFO", string.format("%s completed in %.2fms", name, elapsed_ms)) return elapsed_ms end end -- Validate data types function M.validate_type(value, expected_type) local actual_type = type(value) if expected_type == "number" then return actual_type == "number" elseif expected_type == "string" then return actual_type == "string" elseif expected_type == "boolean" then return actual_type == "boolean" elseif expected_type == "table" then return actual_type == "table" elseif expected_type == "function" then return actual_type == "function" end return false end -- Escape SQL values function M.escape_sql(value) if type(value) == "string" then return "'" .. value:gsub("'", "''") .. "'" elseif type(value) == "number" then return tostring(value) elseif type(value) == "boolean" then return value and "1" or "0" elseif value == nil then return "NULL" else return "'" .. tostring(value):gsub("'", "''") .. "'" end end return M