Skip to content

Formula validation API with detailed error messages #14

Description

@yousira

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 * 1ATK
I002 Consider using built-in a > b ? a : bmax(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)
})

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions