streamling errorhandler calls
This commit is contained in:
10
FlexLove.lua
10
FlexLove.lua
@@ -272,7 +272,7 @@ end
|
|||||||
---@param callback function The callback to execute
|
---@param callback function The callback to execute
|
||||||
function flexlove.deferCallback(callback)
|
function flexlove.deferCallback(callback)
|
||||||
if type(callback) ~= "function" then
|
if type(callback) ~= "function" then
|
||||||
flexlove._ErrorHandler:warn("FlexLove", "deferCallback expects a function")
|
flexlove._ErrorHandler:warn("FlexLove", "CORE_001")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
table.insert(flexlove._deferredCallbacks, callback)
|
table.insert(flexlove._deferredCallbacks, callback)
|
||||||
@@ -300,7 +300,9 @@ function flexlove.executeDeferredCallbacks()
|
|||||||
for _, callback in ipairs(callbacks) do
|
for _, callback in ipairs(callbacks) do
|
||||||
local success, err = xpcall(callback, debug.traceback)
|
local success, err = xpcall(callback, debug.traceback)
|
||||||
if not success then
|
if not success then
|
||||||
flexlove._ErrorHandler:warn("FlexLove", string.format("Deferred callback failed: %s", tostring(err)))
|
flexlove._ErrorHandler:warn("FlexLove", "CORE_002", {
|
||||||
|
error = tostring(err),
|
||||||
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -787,7 +789,9 @@ function flexlove.setGCStrategy(strategy)
|
|||||||
if strategy == "auto" or strategy == "periodic" or strategy == "manual" or strategy == "disabled" then
|
if strategy == "auto" or strategy == "periodic" or strategy == "manual" or strategy == "disabled" then
|
||||||
flexlove._gcConfig.strategy = strategy
|
flexlove._gcConfig.strategy = strategy
|
||||||
else
|
else
|
||||||
flexlove._ErrorHandler:warn("FlexLove", "Invalid GC strategy: " .. tostring(strategy))
|
flexlove._ErrorHandler:warn("FlexLove", "CORE_003", {
|
||||||
|
strategy = tostring(strategy),
|
||||||
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -542,28 +542,28 @@ Animation.__index = Animation
|
|||||||
function Animation.new(props)
|
function Animation.new(props)
|
||||||
if type(props) ~= "table" then
|
if type(props) ~= "table" then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("Animation", "Animation.new() requires a table argument. Using default values.")
|
Animation._ErrorHandler:warn("Animation", "ANIM_001")
|
||||||
end
|
end
|
||||||
props = { duration = 1, start = {}, final = {} }
|
props = { duration = 1, start = {}, final = {} }
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(props.duration) ~= "number" or props.duration <= 0 then
|
if type(props.duration) ~= "number" or props.duration <= 0 then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("Animation", "Animation duration must be a positive number. Using 1 second.")
|
Animation._ErrorHandler:warn("Animation", "ANIM_002")
|
||||||
end
|
end
|
||||||
props.duration = 1
|
props.duration = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(props.start) ~= "table" then
|
if type(props.start) ~= "table" then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("Animation", "Animation start must be a table. Using empty table.")
|
Animation._ErrorHandler:warn("Animation", "ANIM_001")
|
||||||
end
|
end
|
||||||
props.start = {}
|
props.start = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(props.final) ~= "table" then
|
if type(props.final) ~= "table" then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("Animation", "Animation final must be a table. Using empty table.")
|
Animation._ErrorHandler:warn("Animation", "ANIM_001")
|
||||||
end
|
end
|
||||||
props.final = {}
|
props.final = {}
|
||||||
end
|
end
|
||||||
@@ -925,7 +925,7 @@ end
|
|||||||
function Animation:apply(element)
|
function Animation:apply(element)
|
||||||
if not element or type(element) ~= "table" then
|
if not element or type(element) ~= "table" then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("Animation", "Cannot apply animation to nil or non-table element.")
|
Animation._ErrorHandler:warn("Animation", "ANIM_003")
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -1035,7 +1035,7 @@ function Animation:chain(nextAnimation)
|
|||||||
return nextAnimation
|
return nextAnimation
|
||||||
else
|
else
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("Animation", "chain() requires an Animation or function.")
|
Animation._ErrorHandler:warn("Animation", "ANIM_004")
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
@@ -1047,7 +1047,7 @@ end
|
|||||||
function Animation:delay(seconds)
|
function Animation:delay(seconds)
|
||||||
if type(seconds) ~= "number" or seconds < 0 then
|
if type(seconds) ~= "number" or seconds < 0 then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("Animation", "delay() requires a non-negative number. Using 0.")
|
Animation._ErrorHandler:warn("Animation", "ANIM_005")
|
||||||
end
|
end
|
||||||
seconds = 0
|
seconds = 0
|
||||||
end
|
end
|
||||||
@@ -1062,7 +1062,7 @@ end
|
|||||||
function Animation:repeatCount(count)
|
function Animation:repeatCount(count)
|
||||||
if type(count) ~= "number" or count < 0 then
|
if type(count) ~= "number" or count < 0 then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("Animation", "repeatCount() requires a non-negative number. Using 0.")
|
Animation._ErrorHandler:warn("Animation", "ANIM_006")
|
||||||
end
|
end
|
||||||
count = 0
|
count = 0
|
||||||
end
|
end
|
||||||
@@ -1138,21 +1138,21 @@ end
|
|||||||
function Animation.keyframes(props)
|
function Animation.keyframes(props)
|
||||||
if type(props) ~= "table" then
|
if type(props) ~= "table" then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("Animation", "Animation.keyframes() requires a table argument. Using defaults.")
|
Animation._ErrorHandler:warn("Animation", "ANIM_007")
|
||||||
end
|
end
|
||||||
props = { duration = 1, keyframes = {} }
|
props = { duration = 1, keyframes = {} }
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(props.duration) ~= "number" or props.duration <= 0 then
|
if type(props.duration) ~= "number" or props.duration <= 0 then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("Animation", "Keyframe duration must be positive. Using 1 second.")
|
Animation._ErrorHandler:warn("Animation", "ANIM_002")
|
||||||
end
|
end
|
||||||
props.duration = 1
|
props.duration = 1
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(props.keyframes) ~= "table" or #props.keyframes < 2 then
|
if type(props.keyframes) ~= "table" or #props.keyframes < 2 then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("Animation", "Keyframes require at least 2 keyframes. Using empty animation.")
|
Animation._ErrorHandler:warn("Animation", "ANIM_008")
|
||||||
end
|
end
|
||||||
props.keyframes = {
|
props.keyframes = {
|
||||||
{ at = 0, values = {} },
|
{ at = 0, values = {} },
|
||||||
@@ -1224,14 +1224,14 @@ AnimationGroup.__index = AnimationGroup
|
|||||||
function AnimationGroup.new(props)
|
function AnimationGroup.new(props)
|
||||||
if type(props) ~= "table" then
|
if type(props) ~= "table" then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("AnimationGroup", "AnimationGroup.new() requires a table. Using defaults.")
|
Animation._ErrorHandler:warn("AnimationGroup", "ANIM_009")
|
||||||
end
|
end
|
||||||
props = { animations = {} }
|
props = { animations = {} }
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(props.animations) ~= "table" or #props.animations == 0 then
|
if type(props.animations) ~= "table" or #props.animations == 0 then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("AnimationGroup", "AnimationGroup requires at least one animation.")
|
Animation._ErrorHandler:warn("AnimationGroup", "ANIM_010")
|
||||||
end
|
end
|
||||||
props.animations = {}
|
props.animations = {}
|
||||||
end
|
end
|
||||||
@@ -1246,7 +1246,9 @@ function AnimationGroup.new(props)
|
|||||||
|
|
||||||
if self.mode ~= "parallel" and self.mode ~= "sequence" and self.mode ~= "stagger" then
|
if self.mode ~= "parallel" and self.mode ~= "sequence" and self.mode ~= "stagger" then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("AnimationGroup", string.format("Invalid mode: %s. Using 'parallel'.", tostring(self.mode)))
|
Animation._ErrorHandler:warn("AnimationGroup", "ANIM_011", {
|
||||||
|
mode = tostring(self.mode),
|
||||||
|
})
|
||||||
end
|
end
|
||||||
self.mode = "parallel"
|
self.mode = "parallel"
|
||||||
end
|
end
|
||||||
@@ -1512,7 +1514,7 @@ end
|
|||||||
function AnimationGroup:apply(element)
|
function AnimationGroup:apply(element)
|
||||||
if not element or type(element) ~= "table" then
|
if not element or type(element) ~= "table" then
|
||||||
if Animation._ErrorHandler then
|
if Animation._ErrorHandler then
|
||||||
Animation._ErrorHandler:warn("AnimationGroup", "Cannot apply group to nil or non-table element.")
|
Animation._ErrorHandler:warn("AnimationGroup", "ANIM_003")
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -355,7 +355,9 @@ local function checkLargeBlurWarning(elementId, width, height, blurType)
|
|||||||
local suggestion =
|
local suggestion =
|
||||||
"Consider using retained mode for this component to avoid recreating blur effects every frame. Large blur operations are expensive and can cause performance issues in immediate mode."
|
"Consider using retained mode for this component to avoid recreating blur effects every frame. Large blur operations are expensive and can cause performance issues in immediate mode."
|
||||||
|
|
||||||
Blur._ErrorHandler:warn("Blur", "PERF_003", message, suggestion)
|
Blur._ErrorHandler:warn("Blur", "PERF_003", {
|
||||||
|
area = string.format("%.0fx%.0f", width or 0, height or 0),
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a new blur effect instance
|
--- Create a new blur effect instance
|
||||||
@@ -388,7 +390,7 @@ end
|
|||||||
function Blur:applyToRegion(intensity, x, y, width, height, drawFunc)
|
function Blur:applyToRegion(intensity, x, y, width, height, drawFunc)
|
||||||
if type(drawFunc) ~= "function" then
|
if type(drawFunc) ~= "function" then
|
||||||
if Blur._ErrorHandler then
|
if Blur._ErrorHandler then
|
||||||
Blur._ErrorHandler:warn("Blur", "applyToRegion requires a draw function.")
|
Blur._ErrorHandler:warn("Blur", "BLUR_001")
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -467,7 +469,7 @@ end
|
|||||||
function Blur:applyBackdrop(intensity, x, y, width, height, backdropCanvas)
|
function Blur:applyBackdrop(intensity, x, y, width, height, backdropCanvas)
|
||||||
if not backdropCanvas then
|
if not backdropCanvas then
|
||||||
if Blur._ErrorHandler then
|
if Blur._ErrorHandler then
|
||||||
Blur._ErrorHandler:warn("Blur", "applyBackdrop requires a backdrop canvas.")
|
Blur._ErrorHandler:warn("Blur", "BLUR_002")
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -586,7 +588,7 @@ function Blur:applyBackdropCached(intensity, x, y, width, height, backdropCanvas
|
|||||||
-- Not cached, render and cache
|
-- Not cached, render and cache
|
||||||
if not backdropCanvas then
|
if not backdropCanvas then
|
||||||
if Blur._ErrorHandler then
|
if Blur._ErrorHandler then
|
||||||
Blur._ErrorHandler:warn("Blur", "applyBackdrop requires a backdrop canvas.")
|
Blur._ErrorHandler:warn("Blur", "BLUR_002")
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ end
|
|||||||
function Color.fromHex(hexWithTag)
|
function Color.fromHex(hexWithTag)
|
||||||
-- Validate input type
|
-- Validate input type
|
||||||
if type(hexWithTag) ~= "string" then
|
if type(hexWithTag) ~= "string" then
|
||||||
Color._ErrorHandler:warn("Color", "VAL_004", "Invalid color format", {
|
Color._ErrorHandler:warn("Color", "VAL_004", {
|
||||||
input = tostring(hexWithTag),
|
input = tostring(hexWithTag),
|
||||||
issue = "not a string",
|
issue = "not a string",
|
||||||
fallback = "white (#FFFFFF)",
|
fallback = "white (#FFFFFF)",
|
||||||
@@ -69,7 +69,7 @@ function Color.fromHex(hexWithTag)
|
|||||||
local g = tonumber("0x" .. hex:sub(3, 4))
|
local g = tonumber("0x" .. hex:sub(3, 4))
|
||||||
local b = tonumber("0x" .. hex:sub(5, 6))
|
local b = tonumber("0x" .. hex:sub(5, 6))
|
||||||
if not r or not g or not b then
|
if not r or not g or not b then
|
||||||
Color._ErrorHandler:warn("Color", "VAL_004", "Invalid color format", {
|
Color._ErrorHandler:warn("Color", "VAL_004", {
|
||||||
input = hexWithTag,
|
input = hexWithTag,
|
||||||
issue = "invalid hex digits",
|
issue = "invalid hex digits",
|
||||||
fallback = "white (#FFFFFF)",
|
fallback = "white (#FFFFFF)",
|
||||||
@@ -83,7 +83,7 @@ function Color.fromHex(hexWithTag)
|
|||||||
local b = tonumber("0x" .. hex:sub(5, 6))
|
local b = tonumber("0x" .. hex:sub(5, 6))
|
||||||
local a = tonumber("0x" .. hex:sub(7, 8))
|
local a = tonumber("0x" .. hex:sub(7, 8))
|
||||||
if not r or not g or not b or not a then
|
if not r or not g or not b or not a then
|
||||||
Color._ErrorHandler:warn("Color", "VAL_004", "Invalid color format", {
|
Color._ErrorHandler:warn("Color", "VAL_004", {
|
||||||
input = hexWithTag,
|
input = hexWithTag,
|
||||||
issue = "invalid hex digits",
|
issue = "invalid hex digits",
|
||||||
fallback = "white (#FFFFFFFF)",
|
fallback = "white (#FFFFFFFF)",
|
||||||
@@ -92,7 +92,7 @@ function Color.fromHex(hexWithTag)
|
|||||||
end
|
end
|
||||||
return Color.new(r / 255, g / 255, b / 255, a / 255)
|
return Color.new(r / 255, g / 255, b / 255, a / 255)
|
||||||
else
|
else
|
||||||
Color._ErrorHandler:warn("Color", "VAL_004", "Invalid color format", {
|
Color._ErrorHandler:warn("Color", "VAL_004", {
|
||||||
input = hexWithTag,
|
input = hexWithTag,
|
||||||
expected = "#RRGGBB or #RRGGBBAA",
|
expected = "#RRGGBB or #RRGGBBAA",
|
||||||
hexLength = #hex,
|
hexLength = #hex,
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ function Element.new(props)
|
|||||||
|
|
||||||
-- Validate property combinations: passwordMode disables multiline
|
-- Validate property combinations: passwordMode disables multiline
|
||||||
if self.passwordMode and props.multiline then
|
if self.passwordMode and props.multiline then
|
||||||
Element._ErrorHandler:warn("Element", "passwordMode is enabled, multiline will be disabled")
|
Element._ErrorHandler:warn("Element", "ELEM_006")
|
||||||
self.multiline = false
|
self.multiline = false
|
||||||
elseif self.passwordMode then
|
elseif self.passwordMode then
|
||||||
self.multiline = false
|
self.multiline = false
|
||||||
@@ -743,15 +743,16 @@ function Element.new(props)
|
|||||||
-- Pixel units
|
-- Pixel units
|
||||||
self.textSize = value
|
self.textSize = value
|
||||||
else
|
else
|
||||||
Element._ErrorHandler:error(
|
Element._ErrorHandler:error("Element", "ELEM_002", {
|
||||||
"Element",
|
unit = unit,
|
||||||
string.format("Unknown textSize unit '%s'. Valid units: px, %%, vw, vh, ew, eh. Or use presets: xs, sm, md, lg, xl, xxl, 2xl, 3xl, 4xl", unit)
|
})
|
||||||
)
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- Validate pixel textSize value
|
-- Validate pixel textSize value
|
||||||
if props.textSize <= 0 then
|
if props.textSize <= 0 then
|
||||||
Element._ErrorHandler:error("Element", "textSize must be greater than 0, got: " .. tostring(props.textSize))
|
Element._ErrorHandler:error("Element", "ELEM_001", {
|
||||||
|
value = tostring(props.textSize),
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Pixel textSize value
|
-- Pixel textSize value
|
||||||
@@ -3071,13 +3072,15 @@ function Element:setTransition(property, config)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if type(config) ~= "table" then
|
if type(config) ~= "table" then
|
||||||
Element._ErrorHandler:warn("Element", "setTransition() requires a config table. Using default config.")
|
Element._ErrorHandler:warn("Element", "ELEM_003")
|
||||||
config = {}
|
config = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Validate config
|
-- Validate config
|
||||||
if config.duration and (type(config.duration) ~= "number" or config.duration < 0) then
|
if config.duration and (type(config.duration) ~= "number" or config.duration < 0) then
|
||||||
Element._ErrorHandler:warn("Element", "transition duration must be a non-negative number. Using 0.3 seconds.")
|
Element._ErrorHandler:warn("Element", "ELEM_004", {
|
||||||
|
value = tostring(config.duration),
|
||||||
|
})
|
||||||
config.duration = 0.3
|
config.duration = 0.3
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -3095,7 +3098,7 @@ end
|
|||||||
---@param properties table Array of property names
|
---@param properties table Array of property names
|
||||||
function Element:setTransitionGroup(groupName, config, properties)
|
function Element:setTransitionGroup(groupName, config, properties)
|
||||||
if type(properties) ~= "table" then
|
if type(properties) ~= "table" then
|
||||||
Element._ErrorHandler:warn("Element", "setTransitionGroup() requires a properties array. No transitions set.")
|
Element._ErrorHandler:warn("Element", "ELEM_005")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -313,6 +313,170 @@ local ErrorCodes = {
|
|||||||
description = "CallSite counters accumulating",
|
description = "CallSite counters accumulating",
|
||||||
suggestion = "This indicates incrementFrame() may not be called properly. Check immediate mode frame management.",
|
suggestion = "This indicates incrementFrame() may not be called properly. Check immediate mode frame management.",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
-- Animation Errors (ANIM_001 - ANIM_099)
|
||||||
|
ANIM_001 = {
|
||||||
|
code = "FLEXLOVE_ANIM_001",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid animation configuration",
|
||||||
|
suggestion = "Animation.new() requires a table argument with duration, start, and final properties",
|
||||||
|
},
|
||||||
|
ANIM_002 = {
|
||||||
|
code = "FLEXLOVE_ANIM_002",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid animation duration",
|
||||||
|
suggestion = "Animation duration must be a positive number in seconds",
|
||||||
|
},
|
||||||
|
ANIM_003 = {
|
||||||
|
code = "FLEXLOVE_ANIM_003",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid animation target",
|
||||||
|
suggestion = "Animation can only be applied to table elements",
|
||||||
|
},
|
||||||
|
ANIM_004 = {
|
||||||
|
code = "FLEXLOVE_ANIM_004",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid animation chain",
|
||||||
|
suggestion = "chain() requires an Animation object or function",
|
||||||
|
},
|
||||||
|
ANIM_005 = {
|
||||||
|
code = "FLEXLOVE_ANIM_005",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid animation delay",
|
||||||
|
suggestion = "delay() requires a non-negative number in seconds",
|
||||||
|
},
|
||||||
|
ANIM_006 = {
|
||||||
|
code = "FLEXLOVE_ANIM_006",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid repeat count",
|
||||||
|
suggestion = "repeatCount() requires a non-negative number",
|
||||||
|
},
|
||||||
|
ANIM_007 = {
|
||||||
|
code = "FLEXLOVE_ANIM_007",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid keyframes configuration",
|
||||||
|
suggestion = "Animation.keyframes() requires a table with duration and keyframes array",
|
||||||
|
},
|
||||||
|
ANIM_008 = {
|
||||||
|
code = "FLEXLOVE_ANIM_008",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Insufficient keyframes",
|
||||||
|
suggestion = "Keyframe animations require at least 2 keyframes",
|
||||||
|
},
|
||||||
|
ANIM_009 = {
|
||||||
|
code = "FLEXLOVE_ANIM_009",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid animation group configuration",
|
||||||
|
suggestion = "AnimationGroup.new() requires a table with animations array",
|
||||||
|
},
|
||||||
|
ANIM_010 = {
|
||||||
|
code = "FLEXLOVE_ANIM_010",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Empty animation group",
|
||||||
|
suggestion = "AnimationGroup requires at least one animation",
|
||||||
|
},
|
||||||
|
ANIM_011 = {
|
||||||
|
code = "FLEXLOVE_ANIM_011",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid animation group mode",
|
||||||
|
suggestion = "AnimationGroup mode must be 'parallel' or 'sequence'",
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Blur Errors (BLUR_001 - BLUR_099)
|
||||||
|
BLUR_001 = {
|
||||||
|
code = "FLEXLOVE_BLUR_001",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Missing draw function",
|
||||||
|
suggestion = "applyToRegion requires a draw function to render the content to be blurred",
|
||||||
|
},
|
||||||
|
BLUR_002 = {
|
||||||
|
code = "FLEXLOVE_BLUR_002",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Missing backdrop canvas",
|
||||||
|
suggestion = "applyBackdrop requires a backdrop canvas parameter",
|
||||||
|
},
|
||||||
|
|
||||||
|
-- FlexLove Core Errors (CORE_001 - CORE_099)
|
||||||
|
CORE_001 = {
|
||||||
|
code = "FLEXLOVE_CORE_001",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid callback function",
|
||||||
|
suggestion = "deferCallback expects a function argument",
|
||||||
|
},
|
||||||
|
CORE_002 = {
|
||||||
|
code = "FLEXLOVE_CORE_002",
|
||||||
|
category = "SYS",
|
||||||
|
description = "Deferred callback execution failed",
|
||||||
|
suggestion = "Check the callback function for errors. Error details included in message.",
|
||||||
|
},
|
||||||
|
CORE_003 = {
|
||||||
|
code = "FLEXLOVE_CORE_003",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid garbage collection strategy",
|
||||||
|
suggestion = "GC strategy must be one of: 'default', 'aggressive', 'conservative'",
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Element Errors (ELEM_001 - ELEM_099)
|
||||||
|
ELEM_001 = {
|
||||||
|
code = "FLEXLOVE_ELEM_001",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid text size",
|
||||||
|
suggestion = "textSize must be greater than 0",
|
||||||
|
},
|
||||||
|
ELEM_002 = {
|
||||||
|
code = "FLEXLOVE_ELEM_002",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid text size unit",
|
||||||
|
suggestion = "textSize unit must be one of: px, %, vw, vh, ew, eh, or presets: xs, sm, md, lg, xl, xxl, 2xl, 3xl, 4xl",
|
||||||
|
},
|
||||||
|
ELEM_003 = {
|
||||||
|
code = "FLEXLOVE_ELEM_003",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid transition configuration",
|
||||||
|
suggestion = "setTransition() requires a table with transition properties",
|
||||||
|
},
|
||||||
|
ELEM_004 = {
|
||||||
|
code = "FLEXLOVE_ELEM_004",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid transition duration",
|
||||||
|
suggestion = "Transition duration must be a non-negative number in seconds",
|
||||||
|
},
|
||||||
|
ELEM_005 = {
|
||||||
|
code = "FLEXLOVE_ELEM_005",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Invalid transition group",
|
||||||
|
suggestion = "setTransitionGroup() requires an array of property names",
|
||||||
|
},
|
||||||
|
ELEM_006 = {
|
||||||
|
code = "FLEXLOVE_ELEM_006",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Incompatible element configuration",
|
||||||
|
suggestion = "passwordMode and multiline cannot be used together. Multiline will be disabled.",
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Module Loader Warnings (MOD_001 - MOD_099)
|
||||||
|
MOD_001 = {
|
||||||
|
code = "FLEXLOVE_MOD_001",
|
||||||
|
category = "RES",
|
||||||
|
description = "Optional module not found",
|
||||||
|
suggestion = "Using stub implementation for optional module. This is expected if the module is not required.",
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Utility Errors (UTIL_001 - UTIL_099)
|
||||||
|
UTIL_001 = {
|
||||||
|
code = "FLEXLOVE_UTIL_001",
|
||||||
|
category = "VAL",
|
||||||
|
description = "Text truncation warning",
|
||||||
|
suggestion = "Text was truncated to fit within the maximum allowed length",
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Image/Rendering Errors (IMG_001 - IMG_099)
|
||||||
|
IMG_001 = {
|
||||||
|
code = "FLEXLOVE_IMG_001",
|
||||||
|
category = "REN",
|
||||||
|
description = "Stencil buffer not available",
|
||||||
|
suggestion = "Cannot apply corner radius to image without stencil buffer support. Check graphics capabilities.",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -670,64 +834,33 @@ function ErrorHandler:_formatStackTrace(level)
|
|||||||
return ""
|
return ""
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Format an error or warning message with optional error code
|
--- Format an error or warning message using error code lookup
|
||||||
---@param module string The module name (e.g., "Element", "Units", "Theme")
|
---@param module string The module name (e.g., "Element", "Units", "Theme")
|
||||||
---@param level string "Error" or "Warning"
|
---@param level string "Error" or "Warning"
|
||||||
---@param codeOrMessage string Error code (e.g., "VAL_001") or message
|
---@param code string Error code (e.g., "VAL_001")
|
||||||
---@param messageOrDetails string|table|nil Message or details object
|
---@param details table|nil Optional details object
|
||||||
---@param detailsOrSuggestion table|string|nil Details or suggestion
|
|
||||||
---@param suggestionOrNil string|nil Suggestion
|
|
||||||
---@return string Formatted message
|
---@return string Formatted message
|
||||||
function ErrorHandler:_formatMessage(module, level, codeOrMessage, messageOrDetails, detailsOrSuggestion, suggestionOrNil)
|
function ErrorHandler:_formatMessage(module, level, code, details)
|
||||||
local code = nil
|
local codeInfo = ErrorCodes.get(code)
|
||||||
local message = codeOrMessage
|
|
||||||
local details = nil
|
|
||||||
local suggestion = nil
|
|
||||||
|
|
||||||
-- Parse arguments (support multiple signatures)
|
if not codeInfo then
|
||||||
if type(codeOrMessage) == "string" and ErrorCodes.get(codeOrMessage) then
|
return string.format("[FlexLove - %s] %s: Unknown error code: %s", module, level, code)
|
||||||
-- Called with error code
|
|
||||||
code = codeOrMessage
|
|
||||||
message = messageOrDetails or ErrorCodes.describe(code)
|
|
||||||
|
|
||||||
if type(detailsOrSuggestion) == "table" then
|
|
||||||
details = detailsOrSuggestion
|
|
||||||
suggestion = suggestionOrNil or ErrorCodes.getSuggestion(code)
|
|
||||||
elseif type(detailsOrSuggestion) == "string" then
|
|
||||||
suggestion = detailsOrSuggestion
|
|
||||||
else
|
|
||||||
suggestion = ErrorCodes.getSuggestion(code)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
-- Called with message only (backward compatibility)
|
|
||||||
message = codeOrMessage
|
|
||||||
if type(messageOrDetails) == "table" then
|
|
||||||
details = messageOrDetails
|
|
||||||
suggestion = detailsOrSuggestion
|
|
||||||
elseif type(messageOrDetails) == "string" then
|
|
||||||
suggestion = messageOrDetails
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Build formatted message
|
-- Build formatted message
|
||||||
local parts = {}
|
local parts = {}
|
||||||
|
|
||||||
-- Header: [FlexLove - Module] Level [CODE]: Message
|
-- Header: [FlexLove - Module] Level [CODE]: Description
|
||||||
if code then
|
table.insert(parts, string.format("[FlexLove - %s] %s [%s]: %s", module, level, codeInfo.code, codeInfo.description))
|
||||||
local codeInfo = ErrorCodes.get(code)
|
|
||||||
table.insert(parts, string.format("[FlexLove - %s] %s [%s]: %s", module, level, codeInfo.code, message))
|
|
||||||
else
|
|
||||||
table.insert(parts, string.format("[FlexLove - %s] %s: %s", module, level, message))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Details section
|
-- Details section
|
||||||
if details then
|
if details and type(details) == "table" then
|
||||||
table.insert(parts, self:_formatDetails(details))
|
table.insert(parts, self:_formatDetails(details))
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Suggestion section
|
-- Suggestion section
|
||||||
if suggestion and suggestion ~= "" then
|
if codeInfo.suggestion and codeInfo.suggestion ~= "" then
|
||||||
table.insert(parts, string.format("\n\nSuggestion: %s", suggestion))
|
table.insert(parts, string.format("\n\nSuggestion: %s", codeInfo.suggestion))
|
||||||
end
|
end
|
||||||
|
|
||||||
return table.concat(parts, "")
|
return table.concat(parts, "")
|
||||||
@@ -807,43 +940,17 @@ end
|
|||||||
|
|
||||||
--- Throw a critical error (stops execution)
|
--- Throw a critical error (stops execution)
|
||||||
---@param module string The module name
|
---@param module string The module name
|
||||||
---@param codeOrMessage string Error code or message
|
---@param code string Error code (e.g., "VAL_001")
|
||||||
---@param messageOrDetails string|table|nil Message or details
|
---@param details table|nil Optional details object
|
||||||
---@param detailsOrSuggestion table|string|nil Details or suggestion
|
function ErrorHandler:error(module, code, details)
|
||||||
---@param suggestion string|nil Suggestion
|
local formattedMessage = self:_formatMessage(module, "Error", code, details)
|
||||||
function ErrorHandler:error(module, codeOrMessage, messageOrDetails, detailsOrSuggestion, suggestion)
|
|
||||||
local formattedMessage = self:_formatMessage(module, "Error", codeOrMessage, messageOrDetails, detailsOrSuggestion, suggestion)
|
|
||||||
|
|
||||||
-- Parse arguments for logging
|
local codeInfo = ErrorCodes.get(code)
|
||||||
local code = nil
|
local message = codeInfo and codeInfo.description or code
|
||||||
local message = codeOrMessage
|
local suggestion = codeInfo and codeInfo.suggestion or nil
|
||||||
local details = nil
|
|
||||||
local logSuggestion = nil
|
|
||||||
|
|
||||||
if type(codeOrMessage) == "string" and ErrorCodes.get(codeOrMessage) then
|
|
||||||
code = codeOrMessage
|
|
||||||
message = messageOrDetails or ErrorCodes.describe(code)
|
|
||||||
|
|
||||||
if type(detailsOrSuggestion) == "table" then
|
|
||||||
details = detailsOrSuggestion
|
|
||||||
logSuggestion = suggestion or ErrorCodes.getSuggestion(code)
|
|
||||||
elseif type(detailsOrSuggestion) == "string" then
|
|
||||||
logSuggestion = detailsOrSuggestion
|
|
||||||
else
|
|
||||||
logSuggestion = ErrorCodes.getSuggestion(code)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
message = codeOrMessage
|
|
||||||
if type(messageOrDetails) == "table" then
|
|
||||||
details = messageOrDetails
|
|
||||||
logSuggestion = detailsOrSuggestion
|
|
||||||
elseif type(messageOrDetails) == "string" then
|
|
||||||
logSuggestion = messageOrDetails
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Log the error
|
-- Log the error
|
||||||
self:_writeLog("ERROR", LOG_LEVEL.ERROR, module, code, message, details, logSuggestion)
|
self:_writeLog("ERROR", LOG_LEVEL.ERROR, module, code, message, details, suggestion)
|
||||||
|
|
||||||
if self.includeStackTrace then
|
if self.includeStackTrace then
|
||||||
formattedMessage = formattedMessage .. self:_formatStackTrace(3)
|
formattedMessage = formattedMessage .. self:_formatStackTrace(3)
|
||||||
@@ -854,41 +961,15 @@ end
|
|||||||
|
|
||||||
--- Print a warning (non-critical, continues execution)
|
--- Print a warning (non-critical, continues execution)
|
||||||
---@param module string The module name
|
---@param module string The module name
|
||||||
---@param codeOrMessage string Warning code or message
|
---@param code string Warning code (e.g., "VAL_001")
|
||||||
---@param messageOrDetails string|table|nil Message or details
|
---@param details table|nil Optional details object
|
||||||
---@param detailsOrSuggestion table|string|nil Details or suggestion
|
function ErrorHandler:warn(module, code, details)
|
||||||
---@param suggestion string|nil Suggestion
|
local codeInfo = ErrorCodes.get(code)
|
||||||
function ErrorHandler:warn(module, codeOrMessage, messageOrDetails, detailsOrSuggestion, suggestion)
|
local message = codeInfo and codeInfo.description or code
|
||||||
-- Parse arguments for logging
|
local suggestion = codeInfo and codeInfo.suggestion or nil
|
||||||
local code = nil
|
|
||||||
local message = codeOrMessage
|
|
||||||
local details = nil
|
|
||||||
local logSuggestion = nil
|
|
||||||
|
|
||||||
if type(codeOrMessage) == "string" and ErrorCodes.get(codeOrMessage) then
|
|
||||||
code = codeOrMessage
|
|
||||||
message = messageOrDetails or ErrorCodes.describe(code)
|
|
||||||
|
|
||||||
if type(detailsOrSuggestion) == "table" then
|
|
||||||
details = detailsOrSuggestion
|
|
||||||
logSuggestion = suggestion or ErrorCodes.getSuggestion(code)
|
|
||||||
elseif type(detailsOrSuggestion) == "string" then
|
|
||||||
logSuggestion = detailsOrSuggestion
|
|
||||||
else
|
|
||||||
logSuggestion = ErrorCodes.getSuggestion(code)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
message = codeOrMessage
|
|
||||||
if type(messageOrDetails) == "table" then
|
|
||||||
details = messageOrDetails
|
|
||||||
logSuggestion = detailsOrSuggestion
|
|
||||||
elseif type(messageOrDetails) == "string" then
|
|
||||||
logSuggestion = messageOrDetails
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Log the warning
|
-- Log the warning
|
||||||
self:_writeLog("WARNING", LOG_LEVEL.WARNING, module, code, message, details, logSuggestion)
|
self:_writeLog("WARNING", LOG_LEVEL.WARNING, module, code, message, details, suggestion)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Validate that a value is not nil
|
--- Validate that a value is not nil
|
||||||
|
|||||||
@@ -633,9 +633,9 @@ function EventHandler:_invokeCallback(element, event)
|
|||||||
self.onEvent(element, event)
|
self.onEvent(element, event)
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
EventHandler._ErrorHandler:error("EventHandler", "SYS_003", "FlexLove.deferCallback not available", {
|
EventHandler._ErrorHandler:error("EventHandler", "SYS_003", {
|
||||||
eventType = event.type,
|
eventType = event.type,
|
||||||
}, "Ensure FlexLove module is properly loaded")
|
})
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.onEvent(element, event)
|
self.onEvent(element, event)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ function ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, bounds
|
|||||||
objectPosition = objectPosition or "center center"
|
objectPosition = objectPosition or "center center"
|
||||||
|
|
||||||
if imageWidth <= 0 or imageHeight <= 0 or boundsWidth <= 0 or boundsHeight <= 0 then
|
if imageWidth <= 0 or imageHeight <= 0 or boundsWidth <= 0 or boundsHeight <= 0 then
|
||||||
ErrorHandler:error("ImageRenderer", "VAL_002", "Dimensions must be positive", {
|
ErrorHandler:error("ImageRenderer", "VAL_002", {
|
||||||
imageWidth = imageWidth,
|
imageWidth = imageWidth,
|
||||||
imageHeight = imageHeight,
|
imageHeight = imageHeight,
|
||||||
boundsWidth = boundsWidth,
|
boundsWidth = boundsWidth,
|
||||||
@@ -116,7 +116,7 @@ function ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, bounds
|
|||||||
return ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, boundsHeight, "contain", objectPosition)
|
return ImageRenderer.calculateFit(imageWidth, imageHeight, boundsWidth, boundsHeight, "contain", objectPosition)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
ErrorHandler:warn("ImageRenderer", "VAL_007", string.format("Invalid fit mode: '%s'. Must be one of: fill, contain, cover, scale-down, none", tostring(fitMode)), {
|
ErrorHandler:warn("ImageRenderer", "VAL_007", {
|
||||||
fitMode = fitMode,
|
fitMode = fitMode,
|
||||||
fallback = "fill"
|
fallback = "fill"
|
||||||
})
|
})
|
||||||
@@ -362,7 +362,7 @@ function ImageRenderer.drawTiled(image, x, y, width, height, repeatMode, opacity
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
ErrorHandler:warn("ImageRenderer", "VAL_007", string.format("Invalid repeat mode: '%s'. Using 'no-repeat'", tostring(repeatMode)), {
|
ErrorHandler:warn("ImageRenderer", "VAL_007", {
|
||||||
repeatMode = repeatMode,
|
repeatMode = repeatMode,
|
||||||
fallback = "no-repeat"
|
fallback = "no-repeat"
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -27,11 +27,13 @@ end
|
|||||||
---@return love.ImageData -- Scaled image data
|
---@return love.ImageData -- Scaled image data
|
||||||
function ImageScaler.scaleNearest(sourceImageData, srcX, srcY, srcW, srcH, destW, destH)
|
function ImageScaler.scaleNearest(sourceImageData, srcX, srcY, srcW, srcH, destW, destH)
|
||||||
if not sourceImageData then
|
if not sourceImageData then
|
||||||
ErrorHandler:error("ImageScaler", "VAL_001", "Source ImageData cannot be nil")
|
ErrorHandler:error("ImageScaler", "VAL_001", {
|
||||||
|
parameter = "sourceImageData"
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
if srcW <= 0 or srcH <= 0 or destW <= 0 or destH <= 0 then
|
if srcW <= 0 or srcH <= 0 or destW <= 0 or destH <= 0 then
|
||||||
ErrorHandler:warn("ImageScaler", "VAL_002", "Dimensions must be positive", {
|
ErrorHandler:warn("ImageScaler", "VAL_002", {
|
||||||
srcW = srcW,
|
srcW = srcW,
|
||||||
srcH = srcH,
|
srcH = srcH,
|
||||||
destW = destW,
|
destW = destW,
|
||||||
@@ -95,11 +97,13 @@ end
|
|||||||
---@return love.ImageData -- Scaled image data
|
---@return love.ImageData -- Scaled image data
|
||||||
function ImageScaler.scaleBilinear(sourceImageData, srcX, srcY, srcW, srcH, destW, destH)
|
function ImageScaler.scaleBilinear(sourceImageData, srcX, srcY, srcW, srcH, destW, destH)
|
||||||
if not sourceImageData then
|
if not sourceImageData then
|
||||||
ErrorHandler:error("ImageScaler", "VAL_001", "Source ImageData cannot be nil")
|
ErrorHandler:error("ImageScaler", "VAL_001", {
|
||||||
|
parameter = "sourceImageData"
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
if srcW <= 0 or srcH <= 0 or destW <= 0 or destH <= 0 then
|
if srcW <= 0 or srcH <= 0 or destW <= 0 or destH <= 0 then
|
||||||
ErrorHandler:warn("ImageScaler", "VAL_002", "Dimensions must be positive", {
|
ErrorHandler:warn("ImageScaler", "VAL_002", {
|
||||||
srcW = srcW,
|
srcW = srcW,
|
||||||
srcH = srcH,
|
srcH = srcH,
|
||||||
destW = destW,
|
destW = destW,
|
||||||
|
|||||||
@@ -240,18 +240,18 @@ function LayoutEngine:layoutChildren()
|
|||||||
-- Warn if child uses percentage sizing but parent has autosizing
|
-- Warn if child uses percentage sizing but parent has autosizing
|
||||||
if child.units and child.units.width then
|
if child.units and child.units.width then
|
||||||
if child.units.width.unit == "%" and self.element.autosizing and self.element.autosizing.width then
|
if child.units.width.unit == "%" and self.element.autosizing and self.element.autosizing.width then
|
||||||
LayoutEngine._ErrorHandler:warn("LayoutEngine", "LAY_004", "Invalid sizing combination", {
|
LayoutEngine._ErrorHandler:warn("LayoutEngine", "LAY_004", {
|
||||||
child = child.id or "unnamed",
|
child = child.id or "unnamed",
|
||||||
issue = "percentage width with parent auto-sizing",
|
issue = "percentage width with parent auto-sizing",
|
||||||
}, "Use fixed or viewport units instead of percentage when parent has auto-sizing enabled")
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if child.units and child.units.height then
|
if child.units and child.units.height then
|
||||||
if child.units.height.unit == "%" and self.element.autosizing and self.element.autosizing.height then
|
if child.units.height.unit == "%" and self.element.autosizing and self.element.autosizing.height then
|
||||||
LayoutEngine._ErrorHandler:warn("LayoutEngine", "LAY_004", "Invalid sizing combination", {
|
LayoutEngine._ErrorHandler:warn("LayoutEngine", "LAY_004", {
|
||||||
child = child.id or "unnamed",
|
child = child.id or "unnamed",
|
||||||
issue = "percentage height with parent auto-sizing",
|
issue = "percentage height with parent auto-sizing",
|
||||||
}, "Use fixed or viewport units instead of percentage when parent has auto-sizing enabled")
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -134,7 +134,10 @@ function ModuleLoader.safeRequire(modulePath, isOptional)
|
|||||||
if ModuleLoader._ErrorHandler then
|
if ModuleLoader._ErrorHandler then
|
||||||
ModuleLoader._ErrorHandler:warn(
|
ModuleLoader._ErrorHandler:warn(
|
||||||
"ModuleLoader",
|
"ModuleLoader",
|
||||||
string.format("Optional module '%s' not found, using stub implementation", modulePath)
|
"MOD_001",
|
||||||
|
{
|
||||||
|
modulePath = modulePath
|
||||||
|
}
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -271,16 +271,13 @@ function Performance:_addWarning(name, value, level)
|
|||||||
|
|
||||||
if now - lastWarningTime >= 60 then
|
if now - lastWarningTime >= 60 then
|
||||||
if self._ErrorHandler and self._ErrorHandler.warn then
|
if self._ErrorHandler and self._ErrorHandler.warn then
|
||||||
local message = string.format("%s = %.2fms", name, value)
|
|
||||||
local code = level == "critical" and "PERF_002" or "PERF_001"
|
local code = level == "critical" and "PERF_002" or "PERF_001"
|
||||||
local suggestion = level == "critical" and "This operation is causing frame drops. Consider optimizing or reducing frequency."
|
|
||||||
or "This operation is taking longer than recommended. Monitor for patterns."
|
|
||||||
|
|
||||||
self._ErrorHandler:warn("Performance", code, message, {
|
self._ErrorHandler:warn("Performance", code, {
|
||||||
metric = name,
|
metric = name,
|
||||||
value = string.format("%.2fms", value),
|
value = string.format("%.2fms", value),
|
||||||
threshold = level == "critical" and self.criticalThresholdMs or self.warningThresholdMs,
|
threshold = level == "critical" and self.criticalThresholdMs or self.warningThresholdMs,
|
||||||
}, suggestion)
|
})
|
||||||
else
|
else
|
||||||
local prefix = level == "critical" and "[CRITICAL]" or "[WARNING]"
|
local prefix = level == "critical" and "[CRITICAL]" or "[WARNING]"
|
||||||
print(string.format("%s Performance: %s = %.2fms", prefix, name, value))
|
print(string.format("%s Performance: %s = %.2fms", prefix, name, value))
|
||||||
@@ -405,7 +402,7 @@ function Performance:logWarning(warningKey, module, message, details, suggestion
|
|||||||
end
|
end
|
||||||
|
|
||||||
if self._ErrorHandler and self._ErrorHandler.warn then
|
if self._ErrorHandler and self._ErrorHandler.warn then
|
||||||
self._ErrorHandler:warn(module, "PERF_001", message, details or {}, suggestion)
|
self._ErrorHandler:warn(module, "PERF_001", details or {})
|
||||||
else
|
else
|
||||||
print(string.format("[FlexLove - %s] Performance Warning: %s", module, message))
|
print(string.format("[FlexLove - %s] Performance Warning: %s", module, message))
|
||||||
if suggestion then
|
if suggestion then
|
||||||
@@ -529,12 +526,12 @@ function Performance:_sampleMemory()
|
|||||||
if not self._shownWarnings[name] then
|
if not self._shownWarnings[name] then
|
||||||
local message = string.format("Table '%s' growing consistently", name)
|
local message = string.format("Table '%s' growing consistently", name)
|
||||||
if self._ErrorHandler and self._ErrorHandler.warn then
|
if self._ErrorHandler and self._ErrorHandler.warn then
|
||||||
self._ErrorHandler:warn("Performance", "MEM_001", message, {
|
self._ErrorHandler:warn("Performance", "MEM_001", {
|
||||||
table = name,
|
table = name,
|
||||||
initialSize = sizes[1],
|
initialSize = sizes[1],
|
||||||
currentSize = sizes[#sizes],
|
currentSize = sizes[#sizes],
|
||||||
growthPercent = math.floor(((sizes[#sizes] / sizes[1]) - 1) * 100),
|
growthPercent = math.floor(((sizes[#sizes] / sizes[1]) - 1) * 100),
|
||||||
}, "Check for memory leaks. Review cache eviction policies and ensure objects are released.")
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
self._shownWarnings[name] = true
|
self._shownWarnings[name] = true
|
||||||
|
|||||||
@@ -233,11 +233,11 @@ function Renderer:_drawImage(x, y, paddingLeft, paddingTop, contentWidth, conten
|
|||||||
self.cornerRadius.bottomRight
|
self.cornerRadius.bottomRight
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
Renderer._ErrorHandler:warn("Renderer", "IMG_001", "Cannot apply corner radius to image: stencil buffer not available", {
|
Renderer._ErrorHandler:warn("Renderer", "IMG_001", {
|
||||||
imagePath = self.imagePath or "unknown",
|
imagePath = self.imagePath or "unknown",
|
||||||
cornerRadius = cornerRadiusStr,
|
cornerRadius = cornerRadiusStr,
|
||||||
error = tostring(err),
|
error = tostring(err),
|
||||||
}, "Ensure the active canvas has stencil=true enabled, or remove cornerRadius from images")
|
})
|
||||||
-- Continue without corner radius
|
-- Continue without corner radius
|
||||||
hasCornerRadius = false
|
hasCornerRadius = false
|
||||||
else
|
else
|
||||||
@@ -380,9 +380,9 @@ end
|
|||||||
---@param backdropCanvas table|nil Backdrop canvas for backdrop blur
|
---@param backdropCanvas table|nil Backdrop canvas for backdrop blur
|
||||||
function Renderer:draw(element, backdropCanvas)
|
function Renderer:draw(element, backdropCanvas)
|
||||||
if not element then
|
if not element then
|
||||||
Renderer._ErrorHandler:warn("Renderer", "SYS_002", "Element parameter required", {
|
Renderer._ErrorHandler:warn("Renderer", "SYS_002", {
|
||||||
method = "draw",
|
method = "draw",
|
||||||
}, "Pass element as first parameter to draw()")
|
})
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -270,10 +270,10 @@ function StateManager.getState(id, defaultState)
|
|||||||
if not ErrorHandler then
|
if not ErrorHandler then
|
||||||
ErrorHandler = require("modules.ErrorHandler")
|
ErrorHandler = require("modules.ErrorHandler")
|
||||||
end
|
end
|
||||||
ErrorHandler.error("StateManager", "SYS_001", "Invalid state ID", {
|
ErrorHandler.error("StateManager", "SYS_001", {
|
||||||
parameter = "id",
|
parameter = "id",
|
||||||
value = "nil",
|
value = "nil",
|
||||||
}, "Provide a valid non-nil ID string to getState()")
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Create state if it doesn't exist
|
-- Create state if it doesn't exist
|
||||||
@@ -306,10 +306,10 @@ function StateManager.setState(id, state)
|
|||||||
if not ErrorHandler then
|
if not ErrorHandler then
|
||||||
ErrorHandler = require("modules.ErrorHandler")
|
ErrorHandler = require("modules.ErrorHandler")
|
||||||
end
|
end
|
||||||
ErrorHandler.error("StateManager", "SYS_001", "Invalid state ID", {
|
ErrorHandler.error("StateManager", "SYS_001", {
|
||||||
parameter = "id",
|
parameter = "id",
|
||||||
value = "nil",
|
value = "nil",
|
||||||
}, "Provide a valid non-nil ID string to setState()")
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Create sparse state (remove default values)
|
-- Create sparse state (remove default values)
|
||||||
@@ -529,12 +529,11 @@ function StateManager.getStats()
|
|||||||
-- Warn if callSiteCounters is unexpectedly large
|
-- Warn if callSiteCounters is unexpectedly large
|
||||||
if callSiteCount > 1000 then
|
if callSiteCount > 1000 then
|
||||||
if ErrorHandler then
|
if ErrorHandler then
|
||||||
local message = string.format("callSiteCounters has %d entries (expected near 0 per frame)", callSiteCount)
|
ErrorHandler.warn("StateManager", "STATE_001", {
|
||||||
ErrorHandler.warn("StateManager", "STATE_001", message, {
|
|
||||||
count = callSiteCount,
|
count = callSiteCount,
|
||||||
expected = "near 0",
|
expected = "near 0",
|
||||||
frameNumber = frameNumber,
|
frameNumber = frameNumber,
|
||||||
}, "This indicates incrementFrame() may not be called properly or counters aren't being reset. Check immediate mode frame management.")
|
})
|
||||||
else
|
else
|
||||||
print(string.format("[StateManager] WARNING: callSiteCounters has %d entries", callSiteCount))
|
print(string.format("[StateManager] WARNING: callSiteCounters has %d entries", callSiteCount))
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ local activeTheme = nil
|
|||||||
function Theme.new(definition)
|
function Theme.new(definition)
|
||||||
-- Validate input type first
|
-- Validate input type first
|
||||||
if type(definition) ~= "table" then
|
if type(definition) ~= "table" then
|
||||||
Theme._ErrorHandler:warn("Theme", "THM_001", "Invalid theme definition", {
|
Theme._ErrorHandler:warn("Theme", "THM_001", {
|
||||||
error = "Theme definition must be a table, got " .. type(definition),
|
error = "Theme definition must be a table, got " .. type(definition),
|
||||||
})
|
})
|
||||||
return Theme.new({ name = "fallback", components = {}, colors = {}, fonts = {} })
|
return Theme.new({ name = "fallback", components = {}, colors = {}, fonts = {} })
|
||||||
@@ -379,7 +379,7 @@ function Theme.new(definition)
|
|||||||
-- Validate theme definition
|
-- Validate theme definition
|
||||||
local valid, err = validateThemeDefinition(definition)
|
local valid, err = validateThemeDefinition(definition)
|
||||||
if not valid then
|
if not valid then
|
||||||
Theme._ErrorHandler:warn("Theme", "THM_001", "Invalid theme definition", {
|
Theme._ErrorHandler:warn("Theme", "THM_001", {
|
||||||
error = tostring(err),
|
error = tostring(err),
|
||||||
})
|
})
|
||||||
return Theme.new({ name = "fallback", components = {}, colors = {}, fonts = {} })
|
return Theme.new({ name = "fallback", components = {}, colors = {}, fonts = {} })
|
||||||
@@ -397,7 +397,7 @@ function Theme.new(definition)
|
|||||||
self.atlas = image
|
self.atlas = image
|
||||||
self.atlasData = imageData
|
self.atlasData = imageData
|
||||||
else
|
else
|
||||||
Theme._ErrorHandler:warn("Theme", "RES_001", "Failed to load global atlas", {
|
Theme._ErrorHandler:warn("Theme", "RES_001", {
|
||||||
theme = definition.name,
|
theme = definition.name,
|
||||||
path = resolvedPath,
|
path = resolvedPath,
|
||||||
error = loaderr,
|
error = loaderr,
|
||||||
@@ -425,7 +425,7 @@ function Theme.new(definition)
|
|||||||
local contentHeight = srcHeight - 2
|
local contentHeight = srcHeight - 2
|
||||||
|
|
||||||
if contentWidth <= 0 or contentHeight <= 0 then
|
if contentWidth <= 0 or contentHeight <= 0 then
|
||||||
Theme._ErrorHandler:warn("Theme", "RES_002", "Nine-patch image too small", {
|
Theme._ErrorHandler:warn("Theme", "RES_002", {
|
||||||
width = srcWidth,
|
width = srcWidth,
|
||||||
height = srcHeight,
|
height = srcHeight,
|
||||||
reason = "Image must be larger than 2x2 pixels to have content after stripping 1px border",
|
reason = "Image must be larger than 2x2 pixels to have content after stripping 1px border",
|
||||||
@@ -460,7 +460,7 @@ function Theme.new(definition)
|
|||||||
comp.insets = parseResult.insets
|
comp.insets = parseResult.insets
|
||||||
comp._ninePatchData = parseResult
|
comp._ninePatchData = parseResult
|
||||||
else
|
else
|
||||||
Theme._ErrorHandler:warn("Theme", "RES_003", "Failed to parse nine-patch image", {
|
Theme._ErrorHandler:warn("Theme", "RES_003", {
|
||||||
context = errorContext,
|
context = errorContext,
|
||||||
path = resolvedPath,
|
path = resolvedPath,
|
||||||
error = tostring(parseErr),
|
error = tostring(parseErr),
|
||||||
@@ -481,7 +481,7 @@ function Theme.new(definition)
|
|||||||
comp._loadedAtlasData = imageData
|
comp._loadedAtlasData = imageData
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
Theme._ErrorHandler:warn("Theme", "RES_001", "Failed to load atlas", {
|
Theme._ErrorHandler:warn("Theme", "RES_001", {
|
||||||
context = errorContext,
|
context = errorContext,
|
||||||
path = resolvedPath,
|
path = resolvedPath,
|
||||||
error = tostring(loaderr),
|
error = tostring(loaderr),
|
||||||
@@ -575,12 +575,12 @@ function Theme.load(path)
|
|||||||
if success then
|
if success then
|
||||||
definition = result
|
definition = result
|
||||||
else
|
else
|
||||||
Theme._ErrorHandler:warn("Theme", "RES_004", "Failed to load theme file", {
|
Theme._ErrorHandler:warn("Theme", "RES_004", {
|
||||||
theme = path,
|
theme = path,
|
||||||
tried = themePath,
|
tried = themePath,
|
||||||
error = tostring(result),
|
error = tostring(result),
|
||||||
fallback = "nil (no theme loaded)",
|
fallback = "nil (no theme loaded)",
|
||||||
}, "Check that the theme file exists in the themes/ directory or provide a valid module path")
|
})
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -607,11 +607,11 @@ function Theme.setActive(themeOrName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not activeTheme then
|
if not activeTheme then
|
||||||
Theme._ErrorHandler:warn("Theme", "THM_002", "Failed to set active theme", {
|
Theme._ErrorHandler:warn("Theme", "THM_002", {
|
||||||
theme = tostring(themeOrName),
|
theme = tostring(themeOrName),
|
||||||
reason = "Theme not found or not loaded",
|
reason = "Theme not found or not loaded",
|
||||||
fallback = "current theme unchanged",
|
fallback = "current theme unchanged",
|
||||||
}, "Ensure the theme is loaded with Theme.load() before setting it active")
|
})
|
||||||
-- Keep current activeTheme unchanged (fallback behavior)
|
-- Keep current activeTheme unchanged (fallback behavior)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -23,48 +23,48 @@ function Units.parse(value)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if type(value) ~= "string" then
|
if type(value) ~= "string" then
|
||||||
Units._ErrorHandler:warn("Units", "VAL_001", "Invalid property type", {
|
Units._ErrorHandler:warn("Units", "VAL_001", {
|
||||||
property = "unit value",
|
property = "unit value",
|
||||||
expected = "string or number",
|
expected = "string or number",
|
||||||
got = type(value),
|
got = type(value),
|
||||||
}, "Using fallback: 0px")
|
})
|
||||||
return 0, "px"
|
return 0, "px"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check for unit-only input (e.g., "px", "%", "vw" without a number)
|
-- Check for unit-only input (e.g., "px", "%", "vw" without a number)
|
||||||
local validUnits = { px = true, ["%"] = true, vw = true, vh = true, ew = true, eh = true }
|
local validUnits = { px = true, ["%"] = true, vw = true, vh = true, ew = true, eh = true }
|
||||||
if validUnits[value] then
|
if validUnits[value] then
|
||||||
Units._ErrorHandler:warn("Units", "VAL_005", "Invalid unit format", {
|
Units._ErrorHandler:warn("Units", "VAL_005", {
|
||||||
input = value,
|
input = value,
|
||||||
expected = "number + unit (e.g., '50" .. value .. "')",
|
expected = "number + unit (e.g., '50" .. value .. "')",
|
||||||
}, string.format("Add a numeric value before '%s', like '50%s'. Using fallback: 0px", value, value))
|
})
|
||||||
return 0, "px"
|
return 0, "px"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check for invalid format (space between number and unit)
|
-- Check for invalid format (space between number and unit)
|
||||||
if value:match("%d%s+%a") then
|
if value:match("%d%s+%a") then
|
||||||
Units._ErrorHandler:warn("Units", "VAL_005", "Invalid unit format", {
|
Units._ErrorHandler:warn("Units", "VAL_005", {
|
||||||
input = value,
|
input = value,
|
||||||
issue = "contains space between number and unit",
|
issue = "contains space between number and unit",
|
||||||
}, "Remove spaces: use '50px' not '50 px'. Using fallback: 0px")
|
})
|
||||||
return 0, "px"
|
return 0, "px"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Match number followed by optional unit
|
-- Match number followed by optional unit
|
||||||
local numStr, unit = value:match("^([%-]?[%d%.]+)(.*)$")
|
local numStr, unit = value:match("^([%-]?[%d%.]+)(.*)$")
|
||||||
if not numStr then
|
if not numStr then
|
||||||
Units._ErrorHandler:warn("Units", "VAL_005", "Invalid unit format", {
|
Units._ErrorHandler:warn("Units", "VAL_005", {
|
||||||
input = value,
|
input = value,
|
||||||
}, "Expected format: number + unit (e.g., '50px', '10%', '2vw'). Using fallback: 0px")
|
})
|
||||||
return 0, "px"
|
return 0, "px"
|
||||||
end
|
end
|
||||||
|
|
||||||
local num = tonumber(numStr)
|
local num = tonumber(numStr)
|
||||||
if not num then
|
if not num then
|
||||||
Units._ErrorHandler:warn("Units", "VAL_005", "Invalid unit format", {
|
Units._ErrorHandler:warn("Units", "VAL_005", {
|
||||||
input = value,
|
input = value,
|
||||||
issue = "numeric value cannot be parsed",
|
issue = "numeric value cannot be parsed",
|
||||||
}, "Using fallback: 0px")
|
})
|
||||||
return 0, "px"
|
return 0, "px"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -75,11 +75,11 @@ function Units.parse(value)
|
|||||||
|
|
||||||
-- validUnits is already defined at the top of the function
|
-- validUnits is already defined at the top of the function
|
||||||
if not validUnits[unit] then
|
if not validUnits[unit] then
|
||||||
Units._ErrorHandler:warn("Units", "VAL_005", "Invalid unit format", {
|
Units._ErrorHandler:warn("Units", "VAL_005", {
|
||||||
input = value,
|
input = value,
|
||||||
unit = unit,
|
unit = unit,
|
||||||
validUnits = "px, %, vw, vh, ew, eh",
|
validUnits = "px, %, vw, vh, ew, eh",
|
||||||
}, string.format("Treating '%s' as pixels", value))
|
})
|
||||||
return num, "px"
|
return num, "px"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -99,10 +99,10 @@ function Units.resolve(value, unit, viewportWidth, viewportHeight, parentSize)
|
|||||||
return value
|
return value
|
||||||
elseif unit == "%" then
|
elseif unit == "%" then
|
||||||
if not parentSize then
|
if not parentSize then
|
||||||
Units._ErrorHandler:warn("Units", "LAY_003", "Invalid dimensions", {
|
Units._ErrorHandler:warn("Units", "LAY_003", {
|
||||||
unit = "%",
|
unit = "%",
|
||||||
issue = "parent dimension not available",
|
issue = "parent dimension not available",
|
||||||
}, "Percentage units require a parent element with explicit dimensions. Using fallback: 0px")
|
})
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
return (value / 100) * parentSize
|
return (value / 100) * parentSize
|
||||||
@@ -111,10 +111,10 @@ function Units.resolve(value, unit, viewportWidth, viewportHeight, parentSize)
|
|||||||
elseif unit == "vh" then
|
elseif unit == "vh" then
|
||||||
return (value / 100) * viewportHeight
|
return (value / 100) * viewportHeight
|
||||||
else
|
else
|
||||||
Units._ErrorHandler:warn("Units", "VAL_005", "Invalid unit format", {
|
Units._ErrorHandler:warn("Units", "VAL_005", {
|
||||||
unit = unit,
|
unit = unit,
|
||||||
validUnits = "px, %, vw, vh, ew, eh",
|
validUnits = "px, %, vw, vh, ew, eh",
|
||||||
}, string.format("Unknown unit type: '%s'. Using fallback: 0px", unit))
|
})
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -342,7 +342,11 @@ local function validateEnum(value, enumTable, propName, moduleName)
|
|||||||
table.sort(validOptions)
|
table.sort(validOptions)
|
||||||
|
|
||||||
if ErrorHandler then
|
if ErrorHandler then
|
||||||
ErrorHandler:error(moduleName or "Element", string.format("%s must be one of: %s. Got: '%s'", propName, table.concat(validOptions, ", "), tostring(value)))
|
ErrorHandler:error(moduleName or "Element", "VAL_007", {
|
||||||
|
property = propName,
|
||||||
|
expected = table.concat(validOptions, ", "),
|
||||||
|
got = tostring(value),
|
||||||
|
})
|
||||||
else
|
else
|
||||||
error(string.format("%s must be one of: %s. Got: '%s'", propName, table.concat(validOptions, ", "), tostring(value)))
|
error(string.format("%s must be one of: %s. Got: '%s'", propName, table.concat(validOptions, ", "), tostring(value)))
|
||||||
end
|
end
|
||||||
@@ -361,17 +365,22 @@ local function validateRange(value, min, max, propName, moduleName)
|
|||||||
end
|
end
|
||||||
if type(value) ~= "number" then
|
if type(value) ~= "number" then
|
||||||
if ErrorHandler then
|
if ErrorHandler then
|
||||||
ErrorHandler:error(moduleName or "Element", string.format("%s must be a number, got %s", propName, type(value)))
|
ErrorHandler:error(moduleName or "Element", "VAL_001", {
|
||||||
|
property = propName,
|
||||||
|
expected = "number",
|
||||||
|
got = type(value),
|
||||||
|
})
|
||||||
else
|
else
|
||||||
error(string.format("%s must be a number, got %s", propName, type(value)))
|
error(string.format("%s must be a number, got %s", propName, type(value)))
|
||||||
end
|
end
|
||||||
end
|
elseif value < min or value > max then
|
||||||
if value < min or value > max then
|
|
||||||
if ErrorHandler then
|
if ErrorHandler then
|
||||||
ErrorHandler:error(
|
ErrorHandler:error(moduleName or "Element", "VAL_002", {
|
||||||
moduleName or "Element",
|
property = propName,
|
||||||
string.format("%s must be between %s and %s, got %s", propName, tostring(min), tostring(max), tostring(value))
|
min = tostring(min),
|
||||||
)
|
max = tostring(max),
|
||||||
|
value = tostring(value),
|
||||||
|
})
|
||||||
else
|
else
|
||||||
error(string.format("%s must be between %s and %s, got %s", propName, tostring(min), tostring(max), tostring(value)))
|
error(string.format("%s must be between %s and %s, got %s", propName, tostring(min), tostring(max), tostring(value)))
|
||||||
end
|
end
|
||||||
@@ -392,7 +401,11 @@ local function validateType(value, expectedType, propName, moduleName)
|
|||||||
local actualType = type(value)
|
local actualType = type(value)
|
||||||
if actualType ~= expectedType then
|
if actualType ~= expectedType then
|
||||||
if ErrorHandler then
|
if ErrorHandler then
|
||||||
ErrorHandler:error(moduleName or "Element", string.format("%s must be %s, got %s", propName, expectedType, actualType))
|
ErrorHandler:error(moduleName or "Element", "VAL_001", {
|
||||||
|
property = propName,
|
||||||
|
expected = expectedType,
|
||||||
|
got = actualType,
|
||||||
|
})
|
||||||
else
|
else
|
||||||
error(string.format("%s must be %s, got %s", propName, expectedType, actualType))
|
error(string.format("%s must be %s, got %s", propName, expectedType, actualType))
|
||||||
end
|
end
|
||||||
@@ -555,6 +568,12 @@ local function sanitizeText(text, options)
|
|||||||
-- Limit string length (use UTF-8 character count, not byte count)
|
-- Limit string length (use UTF-8 character count, not byte count)
|
||||||
local charCount = utf8.len(text)
|
local charCount = utf8.len(text)
|
||||||
if charCount and charCount > maxLength then
|
if charCount and charCount > maxLength then
|
||||||
|
if ErrorHandler then
|
||||||
|
ErrorHandler:warn("utils", "UTIL_001", {
|
||||||
|
original = charCount,
|
||||||
|
truncated = maxLength,
|
||||||
|
})
|
||||||
|
end
|
||||||
-- Truncate to maxLength UTF-8 characters
|
-- Truncate to maxLength UTF-8 characters
|
||||||
local bytePos = utf8.offset(text, maxLength + 1)
|
local bytePos = utf8.offset(text, maxLength + 1)
|
||||||
if bytePos then
|
if bytePos then
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ end
|
|||||||
|
|
||||||
function TestValidationUtils:testValidateEnum_InvalidValue()
|
function TestValidationUtils:testValidateEnum_InvalidValue()
|
||||||
local testEnum = { VALUE1 = "value1", VALUE2 = "value2" }
|
local testEnum = { VALUE1 = "value1", VALUE2 = "value2" }
|
||||||
luaunit.assertErrorMsgContains("must be one of", function()
|
luaunit.assertErrorMsgContains("VAL_007", function()
|
||||||
utils.validateEnum("invalid", testEnum, "testProp")
|
utils.validateEnum("invalid", testEnum, "testProp")
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
@@ -46,10 +46,10 @@ function TestValidationUtils:testValidateRange_InRange()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function TestValidationUtils:testValidateRange_OutOfRange()
|
function TestValidationUtils:testValidateRange_OutOfRange()
|
||||||
luaunit.assertErrorMsgContains("must be between", function()
|
luaunit.assertErrorMsgContains("VAL_002", function()
|
||||||
utils.validateRange(-1, 0, 10, "testProp")
|
utils.validateRange(-1, 0, 10, "testProp")
|
||||||
end)
|
end)
|
||||||
luaunit.assertErrorMsgContains("must be between", function()
|
luaunit.assertErrorMsgContains("VAL_002", function()
|
||||||
utils.validateRange(11, 0, 10, "testProp")
|
utils.validateRange(11, 0, 10, "testProp")
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
@@ -59,7 +59,7 @@ function TestValidationUtils:testValidateRange_NilValue()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function TestValidationUtils:testValidateRange_WrongType()
|
function TestValidationUtils:testValidateRange_WrongType()
|
||||||
luaunit.assertErrorMsgContains("must be a number", function()
|
luaunit.assertErrorMsgContains("VAL_001", function()
|
||||||
utils.validateRange("not a number", 0, 10, "testProp")
|
utils.validateRange("not a number", 0, 10, "testProp")
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
@@ -73,10 +73,10 @@ function TestValidationUtils:testValidateType_CorrectType()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function TestValidationUtils:testValidateType_WrongType()
|
function TestValidationUtils:testValidateType_WrongType()
|
||||||
luaunit.assertErrorMsgContains("must be string", function()
|
luaunit.assertErrorMsgContains("VAL_001", function()
|
||||||
utils.validateType(123, "string", "testProp")
|
utils.validateType(123, "string", "testProp")
|
||||||
end)
|
end)
|
||||||
luaunit.assertErrorMsgContains("must be number", function()
|
luaunit.assertErrorMsgContains("VAL_001", function()
|
||||||
utils.validateType("hello", "number", "testProp")
|
utils.validateType("hello", "number", "testProp")
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user