Skip to content

HCursor abstract

abstract class HCursor extends ACursor

A successful ACursor positioned at a Json value.

HCursor is the working cursor type for navigation and modification. Concrete subtypes are TopCursor (root), ArrayCursor (inside an array), and ObjectCursor (inside an object).

Inheritance

Object → ACursorHCursor

Constructors

HCursor() const

const HCursor(HCursor? lastCursor, CursorOp? lastOp)
Implementation
dart
const HCursor(super.lastCursor, super.lastOp);

Properties

failed no setter inherited

bool get failed

Returns true if the cursor is in a failed state.

Inherited from ACursor.

Implementation
dart
bool get failed => !succeeded;

hashCode no setter inherited

int get hashCode

The hash code for this object.

A hash code is a single integer which represents the state of the object that affects operator == comparisons.

All objects have hash codes. The default hash code implemented by Object represents only the identity of the object, the same way as the default operator == implementation only considers objects equal if they are identical (see identityHashCode).

If operator == is overridden to use the object state instead, the hash code must also be changed to represent that state, otherwise the object cannot be used in hash based data structures like the default Set and Map implementations.

Hash codes must be the same for objects that are equal to each other according to operator ==. The hash code of an object should only change if the object changes in a way that affects equality. There are no further requirements for the hash codes. They need not be consistent between executions of the same program and there are no distribution guarantees.

Objects that are not equal are allowed to have the same hash code. It is even technically allowed that all instances have the same hash code, but if clashes happen too often, it may reduce the efficiency of hash-based data structures like HashSet or HashMap.

If a subclass overrides hashCode, it should override the operator == operator as well to maintain consistency.

Inherited from Object.

Implementation
dart
external int get hashCode;

index no setter inherited

Option<int> get index

If the cursor is inside a JArray, returns Some with the current index.

Inherited from ACursor.

Implementation
dart
Option<int> get index => none();

key no setter inherited

Option<String> get key

If the cursor is inside a JObject, returns Some with the current key.

Inherited from ACursor.

Implementation
dart
Option<String> get key => none();

keys no setter override

Option<IList<String>> get keys

If the focus is a JObject, returns Some with its keys.

Implementation
dart
@override
Option<IList<String>> get keys =>
    Option.when(() => value is JObject, () => (value as JObject).value.keys);

lastCursor final inherited

final HCursor? lastCursor

The cursor that was active before the last operation, or null at the root.

Inherited from ACursor.

Implementation
dart
final HCursor? lastCursor;

lastOp final inherited

final CursorOp? lastOp

The operation that produced this cursor from lastCursor, or null at the root.

Inherited from ACursor.

Implementation
dart
final CursorOp? lastOp;

pathString no setter inherited

String get pathString

A dot/bracket string representing the current cursor position (e.g. .user.address[0]).

Inherited from ACursor.

Implementation
dart
String get pathString => PathToRoot.toPathString(pathToRoot());

runtimeType no setter inherited

Type get runtimeType

A representation of the runtime type of the object.

Inherited from Object.

Implementation
dart
external Type get runtimeType;

succeeded no setter override

bool get succeeded

Returns true if the cursor is in a successful state.

Implementation
dart
@override
bool get succeeded => true;

value no setter

Json get value

The Json value currently in focus.

Implementation
dart
Json get value;

values no setter override

Option<IList<Json>> get values

If the focus is a JArray, returns Some with its elements.

Implementation
dart
@override
Option<IList<Json>> get values =>
    Option.when(() => value is JArray, () => (value as JArray).value);

Methods

addOp()

HCursor addOp(HCursor cursor, CursorOp op)

Returns a new cursor with the same focus but with cursor/op appended to the history.

Implementation
dart
HCursor addOp(HCursor cursor, CursorOp op);

decode() inherited

DecodeResult<DecodingFailure, A> decode<A>(Decoder<A> decoder)

Decodes the focused value using decoder.

Inherited from ACursor.

Implementation
dart
DecodeResult<A> decode<A>(Decoder<A> decoder) => decoder.tryDecodeC(this);

delete() inherited

ACursor delete()

Delete the focus and move to the parent.

Inherited from ACursor.

Implementation
dart
ACursor delete();

downArray() override

ACursor downArray()

If the focus is a JSON array, move to the first element.

Implementation
dart
@override
ACursor downArray() {
  final self = value;

  if (self is JArray && self.value.nonEmpty) {
    return ArrayCursor(self.value, 0, this, false, this, CursorOp.downArray);
  } else {
    return fail(CursorOp.downArray);
  }
}

downField() override

ACursor downField(String key)

If the focus is a JSON object, move to the value at the given key.

Implementation
dart
@override
ACursor downField(String key) {
  final self = value;
  final op = CursorOp.downField(key);

  if (self is JObject) {
    return self.value.contains(key)
        ? ObjectCursor(self.value, key, this, false, this, op)
        : fail(op);
  } else {
    return fail(op);
  }
}

downN() override

ACursor downN(int n)

If the focus is a JSON array, move to element at the given index.

Implementation
dart
@override
ACursor downN(int n) {
  final self = value;

  if (self is JArray && 0 <= n && n < self.value.size) {
    return ArrayCursor(self.value, n, this, false, this, CursorOp.downN(n));
  } else {
    return fail(CursorOp.downN(n));
  }
}

fail()

ACursor fail(CursorOp op)

Returns a FailedCursor recording that op failed from this cursor.

Implementation
dart
ACursor fail(CursorOp op) => FailedCursor(this, op);

field() inherited

ACursor field(String key)

If the focus is a JSON object, move to the sibling at the given key.

Inherited from ACursor.

Implementation
dart
ACursor field(String key);

find()

ACursor find(bool Function(Json) p)

Moves right through array siblings until p returns true for the focused value, or returns a FailedCursor if no element matches.

Implementation
dart
ACursor find(Function1<Json, bool> p) {
  var current = this as ACursor;

  while (current is HCursor) {
    if (p(current.value)) return current;
    current = current.right();
  }
  return current;
}

focus() override

Option<Json> focus()

Returns Some with the focused Json if the cursor succeeded, or None if it failed.

Implementation
dart
@override
Option<Json> focus() => Some(value);

get() inherited

DecodeResult<DecodingFailure, A> get<A>(String key, Decoder<A> decoder)

Navigates to key and decodes the value using decoder.

Inherited from ACursor.

Implementation
dart
DecodeResult<A> get<A>(String key, Decoder<A> decoder) => downField(key).decode(decoder);

getOrElse() inherited

DecodeResult<DecodingFailure, A> getOrElse<A>(
  String key,
  Decoder<A> decoder,
  A Function() fallback,
)

Navigates to key and decodes the value; returns fallback if the field is absent or decoding yields None.

Inherited from ACursor.

Implementation
dart
DecodeResult<A> getOrElse<A>(String key, Decoder<A> decoder, Function0<A> fallback) =>
    get(key, decoder.optional()).fold(
      (err) => fallback().asRight(),
      (aOpt) => aOpt.fold(() => fallback().asRight(), (a) => a.asRight()),
    );

history() inherited

IList<CursorOp> history()

Returns the list of CursorOps that led to this cursor, most-recent first. Used to reconstruct a path for DecodingFailure messages.

Inherited from ACursor.

Implementation
dart
IList<CursorOp> history() {
  final ops = <CursorOp>[];
  var current = this as ACursor?;

  while (current != null && current.lastOp != null) {
    ops.add(current.lastOp!);
    current = current.lastCursor;
  }

  return ilist(ops);
}

left() inherited

ACursor left()

If the focus is an element in a JSON array, move to the left.

Inherited from ACursor.

Implementation
dart
ACursor left();

noSuchMethod() inherited

dynamic noSuchMethod(Invocation invocation)

Invoked when a nonexistent method or property is accessed.

A dynamic member invocation can attempt to call a member which doesn't exist on the receiving object. Example:

dart
dynamic object = 1;
object.add(42); // Statically allowed, run-time error

This invalid code will invoke the noSuchMethod method of the integer 1 with an Invocation representing the .add(42) call and arguments (which then throws).

Classes can override noSuchMethod to provide custom behavior for such invalid dynamic invocations.

A class with a non-default noSuchMethod invocation can also omit implementations for members of its interface. Example:

dart
class MockList<T> implements List<T> {
  noSuchMethod(Invocation invocation) {
    log(invocation);
    super.noSuchMethod(invocation); // Will throw.
  }
}
void main() {
  MockList().add(42);
}

This code has no compile-time warnings or errors even though the MockList class has no concrete implementation of any of the List interface methods. Calls to List methods are forwarded to noSuchMethod, so this code will log an invocation similar to Invocation.method(#add, [42]) and then throw.

If a value is returned from noSuchMethod, it becomes the result of the original invocation. If the value is not of a type that can be returned by the original invocation, a type error occurs at the invocation.

The default behavior is to throw a NoSuchMethodError.

Inherited from Object.

Implementation
dart
@pragma("vm:entry-point")
@pragma("wasm:entry-point")
external dynamic noSuchMethod(Invocation invocation);

pathToRoot() inherited

PathToRoot pathToRoot()

Reconstructs the full PathToRoot from the cursor chain.

Inherited from ACursor.

Implementation
dart
PathToRoot pathToRoot() {
  &#47;&#47; TODO: Revisit lastCursorParentOrLastCursor
  var currentCursor = this as ACursor?;
  var acc = PathToRoot.empty;

  while (currentCursor != null) {
    if (currentCursor.failed) {
      &#47;&#47; If the cursor is in a failed state, we lose context on what the
      &#47;&#47; attempted last position was. Since we usually want to know this
      &#47;&#47; for error reporting, we use the lastOp to attempt to recover that
      &#47;&#47; state. We only care about operations which imply a path to the
      &#47;&#47; root, such as a field selection.

      final lastCursor = currentCursor.lastCursor;
      final lastOp = currentCursor.lastOp;

      switch (lastOp) {
        case Field _:
          currentCursor = currentCursor.lastCursor;
          acc = acc.prependElem(PathElem.objectKey(lastOp.key));
        case DownField _:
          &#47;&#47; We tried to move down, and then that failed, so the field was missing.
          currentCursor = currentCursor.lastCursor;
          acc = acc.prependElem(PathElem.objectKey(lastOp.key));
        case DownArray _:
          &#47;&#47; We tried to move into an array, but it must have been empty.
          currentCursor = currentCursor.lastCursor;
          acc = acc.prependElem(PathElem.arrayIndex(0));
        case DownN _:
          &#47;&#47; We tried to move into an array at index N, but there was no element there.
          currentCursor = currentCursor.lastCursor;
          acc = acc.prependElem(PathElem.arrayIndex(lastOp.n));
        case MoveLeft _:
          &#47;&#47; We tried to move to before the start of the array.
          currentCursor = currentCursor.lastCursor;
          acc = acc.prependElem(PathElem.arrayIndex(-1));
        case MoveRight _:
          if (lastCursor is ArrayCursor) {
            &#47;&#47; We tried to move to past the end of the array.
            currentCursor = lastCursor.parent;
            acc = acc.prependElem(PathElem.arrayIndex(lastCursor.indexValue + 1));
          } else {
            &#47;&#47; Invalid state, skip for now.
            currentCursor = currentCursor.lastCursor;
          }
        default:
          &#47;&#47; CursorOp.MoveUp or CursorOp.DeleteGoParent, both are move up
          &#47;&#47; events.
          &#47;&#47;
          &#47;&#47; Recalling we are in a failed branch here, this should only
          &#47;&#47; fail if we are already at the top of the tree or if the
          &#47;&#47; cursor state is broken, in either
          &#47;&#47; case this is the only valid action to take.
          currentCursor = currentCursor.lastCursor;
      }
    } else {
      switch (currentCursor) {
        case ArrayCursor _:
          final cursor = currentCursor;
          currentCursor = cursor.parent;
          acc = acc.prependElem(PathElem.arrayIndex(cursor.indexValue));
        case ObjectCursor _:
          final cursor = currentCursor;
          currentCursor = cursor.parent;
          acc = acc.prependElem(PathElem.objectKey(cursor.keyValue));
        case TopCursor _:
          currentCursor = null; &#47;&#47; Exit loop
        default:
          currentCursor = currentCursor.lastCursor;
      }
    }
  }

  return acc;
}

replace()

HCursor replace(Json newValue, HCursor cursor, CursorOp? op)

Returns a new cursor with the focus replaced by newValue, recording cursor as the previous cursor and op as the operation.

Implementation
dart
HCursor replace(Json newValue, HCursor cursor, CursorOp? op);
ACursor right()

If the focus is an element in a JSON array, move to the right.

Inherited from ACursor.

Implementation
dart
ACursor right();

root() override

HCursor root()

Returns the root HCursor of the cursor chain, or null if unavailable.

Implementation
dart
@override
HCursor root() => this is TopCursor ? this : (up() as HCursor).root();

set() inherited

ACursor set(Json j)

Returns a new cursor with the focus replaced by j.

Inherited from ACursor.

Implementation
dart
ACursor set(Json j) => withFocus((_) => j);

success() override

Option<HCursor> success()

Returns Some with this cursor if it succeeded, or None if it failed.

Implementation
dart
@override
Option<HCursor> success() => Some(this);

top() override

Option<Json> top()

Returns Some with the root Json value if the cursor succeeded.

Implementation
dart
@override
Option<Json> top() => Some(root().value);

toString() override

String toString()

A string representation of this object.

Some classes have a default textual representation, often paired with a static parse function (like int.parse). These classes will provide the textual representation as their string representation.

Other classes have no meaningful textual representation that a program will care about. Such classes will typically override toString to provide useful information when inspecting the object, mainly for debugging or logging.

Implementation
dart
@override
String toString() => 'HCursor($lastCursor, $lastOp, $value)';

up() inherited

ACursor up()

Move focus to the parent.

Inherited from ACursor.

Implementation
dart
ACursor up();

withFocus() override

HCursor withFocus(Json Function(Json) f)

Returns a new cursor with the focused Json replaced by f(focused).

Implementation
dart
@override
HCursor withFocus(Function1<Json, Json> f) => replace(f(value), this, null);

Operators

operator ==() inherited

bool operator ==(Object other)

The equality operator.

The default behavior for all Objects is to return true if and only if this object and other are the same object.

Override this method to specify a different equality relation on a class. The overriding method must still be an equivalence relation. That is, it must be:

  • Total: It must return a boolean for all arguments. It should never throw.

  • Reflexive: For all objects o, o == o must be true.

  • Symmetric: For all objects o1 and o2, o1 == o2 and o2 == o1 must either both be true, or both be false.

  • Transitive: For all objects o1, o2, and o3, if o1 == o2 and o2 == o3 are true, then o1 == o3 must be true.

The method should also be consistent over time, so whether two objects are equal should only change if at least one of the objects was modified.

If a subclass overrides the equality operator, it should override the hashCode method as well to maintain consistency.

Inherited from Object.

Implementation
dart
external bool operator ==(Object other);

Static Methods

fromJson()

HCursor fromJson(Json json)

Creates an HCursor positioned at the root of json.

Implementation
dart
static HCursor fromJson(Json json) => TopCursor(json, null, null);