rhizome-node/docs/custom-resolvers/api/resolver-plugin-interface.md

4.4 KiB

ResolverPlugin Interface

Overview

The ResolverPlugin interface defines the contract that all resolver plugins must implement. It provides type-safe access to plugin state and dependencies.

Interface Definition

interface ResolverPlugin<T = unknown, D extends string = never> {
  /**
   * Unique identifier for the plugin
   */
  readonly name: string;

  /**
   * Array of property IDs this plugin depends on
   * @default []
   */
  readonly dependencies?: readonly D[];

  /**
   * Initializes the plugin's state
   * @returns Initial state object
   */
  initialize(): T;

  /**
   * Processes a new value and updates the plugin's state
   * @param currentState Current plugin state
   * @param newValue New value to process
   * @param delta Delta information
   * @param dependencies Resolved states of all declared dependencies
   * @returns Updated plugin state
   */
  update(
    currentState: T,
    newValue: PropertyTypes,
    delta: CollapsedDelta,
    dependencies: DependencyStates<D>
  ): T;

  /**
   * Resolves the final value from the current state
   * @param state Current plugin state
   * @param dependencies Resolved states of all declared dependencies
   * @returns Resolved value or undefined if no value should be set
   */
  resolve(
    state: T,
    dependencies: DependencyStates<D>
  ): PropertyTypes | undefined;
}

Type Parameters

Parameter Description
T Type of the plugin's internal state
D Union type of dependency names (must extend string)

Methods

initialize()

Initializes the plugin's internal state. Called once when the resolver is created.

Returns: T - The initial state object

update(currentState, newValue, delta, dependencies)

Processes a new value and updates the plugin's state.

Parameters:

  • currentState: T - Current plugin state
  • newValue: PropertyTypes - New value to process
  • delta: CollapsedDelta - Delta information
  • dependencies: DependencyStates<D> - Resolved states of all declared dependencies

Returns: T - Updated plugin state

resolve(state, dependencies)

Resolves the final value from the current state.

Parameters:

  • state: T - Current plugin state
  • dependencies: DependencyStates<D> - Resolved states of all declared dependencies

Returns: PropertyTypes | undefined - Resolved value or undefined if no value should be set

Example Implementation

class CounterPlugin implements ResolverPlugin<CounterState> {
  readonly name = 'counter' as const;
  
  initialize(): CounterState {
    return { count: 0 };
  }
  
  update(
    state: CounterState,
    _newValue: unknown,
    _delta: CollapsedDelta,
    _deps: {}
  ): CounterState {
    return { count: state.count + 1 };
  }
  
  resolve(state: CounterState): number {
    return state.count;
  }
}

Best Practices

  1. Immutability: Always return new state objects instead of mutating
  2. Purity: Keep methods pure and side-effect free
  3. Error Handling: Handle unexpected input gracefully
  4. Documentation: Document expected types and behavior

Common Patterns

Accessing Dependencies

class PriceCalculator implements ResolverPlugin<PriceState, 'basePrice' | 'taxRate'> {
  readonly name = 'price-calculator' as const;
  readonly dependencies = ['basePrice', 'taxRate'] as const;
  
  update(
    _state: PriceState,
    _newValue: unknown,
    _delta: CollapsedDelta,
    deps: DependencyStates<'basePrice' | 'taxRate'>,
  ): PriceState {
    const basePrice = deps.basePrice as number;
    const taxRate = deps.taxRate as number;
    return { total: basePrice * (1 + taxRate) };
  }
  
  // ...
}

Optional Dependencies

class OptionalDepPlugin implements ResolverPlugin<State, 'required' | 'optional?'> {
  readonly name = 'optional-dep' as const;
  readonly dependencies = ['required', 'optional?'] as const;
  
  update(
    state: State,
    _newValue: unknown,
    _delta: CollapsedDelta,
    deps: any,
  ): State {
    const required = deps.required as number; // Always present
    const optional = deps['optional?'] as number | undefined; // Might be undefined
    
    // ...
  }
  
  // ...
}