Currently, invalid formulas fail silently or produce cryptic error messages. Game designers using the visual editor need clear, actionable feedback when their formulas contain errors.
Current Behavior
fx.evaluate('ATK * ') // Returns 0 or throws generic error
fx.evaluate('unknown_var + 5') // Silent failure
fx.evaluate('1 / 0') // Returns Infinity (no warning)
Proposed Validation API
ValidationResult Interface
interface ValidationError {
code: string
message: string
position: { start: number; end: number }
severity: 'error' | 'warning' | 'info'
suggestion?: string
}
interface ValidationResult {
valid: boolean
errors: ValidationError[]
warnings: ValidationError[]
ast?: FormulaAST // Parsed AST if valid
variables: string[] // Referenced variables
functions: string[] // Referenced functions
}
Validation Methods
// Full validation with all checks
const result = fx.validate('ATK * (1 - DEF/100)')
if (!result.valid) {
result.errors.forEach(err => {
console.log(`Error at position ${err.position.start}: ${err.message}`)
if (err.suggestion) {
console.log(` Suggestion: ${err.suggestion}`)
}
})
}
// Quick syntax check only
const isValid = fx.isValidSyntax('ATK + 5')
// Validate with custom variable context
const result = fx.validate('ATK + customVar', {
knownVariables: ['ATK', 'DEF', 'HP'],
strictMode: true // Error on unknown variables
})
Error Codes and Messages
Syntax Errors
| Code |
Message |
Example |
E001 |
Unexpected end of expression |
ATK * |
E002 |
Missing closing parenthesis |
(ATK + DEF |
E003 |
Invalid operator |
ATK ** DEF |
E004 |
Empty parentheses |
ATK + () * DEF |
E005 |
Adjacent operators |
ATK + * DEF |
Semantic Errors
| Code |
Message |
Example |
E101 |
Unknown variable: '{name}' |
ATTACK + 5 |
E102 |
Unknown function: '{name}' |
sine(45) |
E103 |
Wrong argument count for '{fn}' |
max(1) |
E104 |
Type mismatch in operation |
"text" + 5 |
Warnings
| Code |
Message |
Example |
W001 |
Division by zero possible |
ATK / level |
W002 |
Result may be NaN |
sqrt(-1) |
W003 |
Overflow risk |
pow(999, 999) |
W004 |
Unused parentheses |
((ATK)) |
W005 |
Always true/false condition |
1 > 0 ? a : b |
Info
| Code |
Message |
Example |
I001 |
Can be simplified |
ATK * 1 → ATK |
I002 |
Consider using built-in |
a > b ? a : b → max(a, b) |
Real-time Validation for Editor
// Debounced validation for editor integration
const validateDebounced = fx.createValidator({
debounceMs: 300,
strictMode: false,
customVariables: gameContext.getAllVariables()
})
inputField.addEventListener('input', (e) => {
const result = validateDebounced(e.target.value)
updateEditorMarkers(result.errors)
updateAutoComplete(result.variables)
})
Position Tracking
const result = fx.validate('ATK + unknownVar * 5')
// result.errors[0]:
// {
// code: 'E101',
// message: "Unknown variable: 'unknownVar'",
// position: { start: 6, end: 16 },
// severity: 'error',
// suggestion: "Did you mean 'ATK' or 'DEF'?"
// }
Batch Validation
// Validate multiple formulas efficiently
const results = fx.validateBatch([
{ id: 'damage', formula: 'ATK * crit' },
{ id: 'heal', formula: 'maxHP * 0.1' },
{ id: 'broken', formula: 'ATK +' }
])
results.invalid.forEach(r => {
console.log(`Formula '${r.id}' has errors:`, r.errors)
})