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

95.65% Statements 22/23
100% Branches 13/13
100% Functions 6/6
95.45% Lines 21/22

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                  336x     336x 336x         7x       1x       4x 4x 16x 16x         4x 4x                     200x 200x   200x 7x 4x             193x 761x 190x       3x               31x      
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;
  }
}