Skip to content

Formula validation API with detailed error messages #14

@yousira

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions