validatePropertyOrMethodAccess method

void validatePropertyOrMethodAccess(
  1. String propertyName,
  2. String objectName,
  3. dynamic obj,
  4. Node node,
)

Validates that a property or method exists on the given object. In case of a typo, it provides suggestions based on Levenshtein distance.

Implementation

void validatePropertyOrMethodAccess(
    String propertyName, String objectName, dynamic obj, Node node) {
  if (obj == null) {
    throw JSException(
      node.line ?? 1,
      'Cannot access property "$propertyName" on null or undefined object "$objectName"',
      detailedError: 'Code: ${_interpreter.getCode(node)}',
      recovery:
          'Make sure the object is properly initialized before accessing its properties.',
    );
  }

  try {
    // Get the property using InvokableController
    InvokableController.getProperty(obj, propertyName);
  } catch (e) {
    if (e is InvalidPropertyException) {
      // If property doesn't exist, check if it's a method
      final hasMethod = obj is Invokable && obj.hasMethod(propertyName);
      if (!hasMethod) {
        // If neither property nor method exists, provide helpful suggestions
        final availableProps = obj is Invokable
            ? [...Invokable.getGettableProperties(obj), ...obj.methods().keys]
            : obj is Map
                ? obj.keys.toList()
                : [];

        final suggestions = availableProps
            .where((prop) =>
                _levenshteinDistance(propertyName, prop.toString()) <= 2)
            .toList();

        var recovery =
            'Check if you have used the correct property name (case sensitive).';
        if (suggestions.isNotEmpty) {
          recovery +=
              '\nDid you mean one of these? ${suggestions.join(", ")}';
        }

        throw JSException(
          node.line ?? 1,
          'Property "$propertyName" does not exist on object "$objectName"',
          detailedError:
              'Code: ${_interpreter.getCode(node)}\nAvailable properties: ${availableProps.join(", ")}',
          recovery: recovery,
        );
      }
    }
    rethrow;
  }
}