All files / src/ast/reference property-or-field-reference.ts

92.06% Statements 58/63
94.44% Branches 17/18
100% Functions 7/7
92.06% Lines 58/63

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76  1x 1x 1x 1x 1x   1x 176x 176x   176x 176x 176x 176x     176x 7x 7x   176x 1x 1x   176x 4x 4x 16x 16x 16x 16x 16x 16x 4x 4x 4x 16x           4x   176x 87x 87x   87x 6x 4x 4x 4x 4x 4x 4x   87x 320x 78x 78x 320x   3x 3x 3x 3x 3x 87x   176x 31x 31x 176x  
import type { ExpressionState } from '../../expression-state.js';
import { TypedValue } from '../../typed-value.js';
import { SpelEvaluationException } from '../../error/spel-evaluation-exception.js';
import { SpelMessage } from '../../error/spel-message.js';
import { SpelNodeImpl } from '../spel-node.js';
import { NodeType } from '../../language/node-type.js';
 
export class PropertyOrFieldReference extends SpelNodeImpl {
  private readonly name: string;
  public nullSafe = false;
 
  constructor(startPos: number, endPos: number, name: string) {
    super(NodeType.PROPERTY_OR_FIELD_REFERENCE, startPos, endPos);
    this.name = name;
  }
 
  /** Get the property/field name */
  public getName(): string {
    return this.name;
  }
 
  public override isWritable(_state: ExpressionState): boolean {
    return true;
  }
 
  public override setValue(state: ExpressionState, newValue: unknown): void {
    const context = state.getEvaluationContext();
    for (const accessor of context.getPropertyAccessors()) {
      const rootObj = state.getThis().getValue();
      if (
        rootObj !== null &&
        rootObj !== undefined &&
        accessor.canWrite(context, rootObj, this.name)
      ) {
        accessor.write(context, rootObj, this.name, newValue);
        return;
      }
    }
    throw new SpelEvaluationException(
      this.startPos,
      SpelMessage.PROPERTY_OR_FIELD_NOT_WRITABLE,
      this.name,
    );
  }
 
  public getValueInternal(state: ExpressionState): TypedValue {
    const target = state.getThis().getValue();
    const context = state.getEvaluationContext();
 
    if (target === null || target === undefined) {
      if (this.nullSafe) return TypedValue.NULL;
      throw new SpelEvaluationException(
        this.startPos,
        SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE_ON_NULL,
        this.name,
      );
    }
 
    for (const accessor of context.getPropertyAccessors()) {
      if (accessor.canRead(context, target, this.name)) {
        return accessor.read(context, target, this.name);
      }
    }
 
    throw new SpelEvaluationException(
      this.startPos,
      SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE,
      this.name,
    );
  }
 
  public toStringAST(): string {
    return this.name;
  }
}