> For the complete documentation index, see [llms.txt](https://docs.rierino.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rierino.com/design/pro-code/modules/object-utilities.md).

# Object utilities

A built-in module allows easy manipulation of JSON records

```jsx
import objectutils from "operations/objectutils";
```

Path access, object shaping and expression evaluation. This is the helper you will reach for most often when working with record data.

> Call every method **on the object**, as in `objectutils.eval(...)`, not `const { eval } = objectutils`. These methods depend on their own context and will not work when destructured.

***

## Path syntax

Paths are dotted. Wrap a segment in square brackets when the segment itself contains a dot:

```
data.title
data.prices[tr-TR].amount
list.0.name
```

`splitPath(path, useIndex = false)` returns the segments. Pass `useIndex: true` when numeric segments should be real array indexes rather than string keys.

***

## Expressions

Rierino uses JMESPath for expressions, extended with its own set of functions, summarised under Expression functions below.

#### `eval(obj, expression, throwError = false)`

Runs an expression **synchronously**.

```js
objectutils.eval(item, "data.variants[?stock > `0`].sku");
```

Because it is synchronous, the async-only functions (notably `lookup`) cannot resolve here and return `null`. For those, use `evalExp` from EvalProvider.

#### `evalOrValue(obj, q, defaultValue = null)`

If `q` is a string starting with `=`, the rest is evaluated as an expression. Otherwise `q` is returned as a literal.

```js
objectutils.evalOrValue(ctx, "=_meta.user.name");  // evaluated
objectutils.evalOrValue(ctx, "Acme");              // literal
objectutils.evalOrValue(ctx, null);                // defaultValue
```

This is the convention behind configuration fields named `value`, such as filter defaults and new-record defaults.

#### `evalOrPath(obj, q, defaultValue = null)`

Three-way dispatch on the prefix:

| Prefix   | Behaviour                               |
| -------- | --------------------------------------- |
| `==`     | return the rest as a **literal string** |
| `=`      | evaluate the rest as an expression      |
| *(none)* | treat `q` as a plain **path**           |

This is the convention behind configuration fields that accept either a path or an expression, such as `id`, `name` and `icon`.

***

## Reading and writing values

| Method               | Signature                                                 | Notes                                                                                                                                                                           |
| -------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `getPathElement`     | `(obj, path, defaultValue = null, useIndex = false)`      | safe deep read                                                                                                                                                                  |
| `setPathElement`     | `(obj, path, value, deleteNull = true, useIndex = false)` | deep write, creating intermediate objects along the way                                                                                                                         |
| `splitPath`          | `(path, useIndex = false)`                                |                                                                                                                                                                                 |
| `getArrayAndIndex`   | `(root, itemPath)`                                        | `{ arr, index }` for a path ending in an array index; throws if the parent is not an array or the index is out of range                                                         |
| `moveRelativeToPath` | `(root, dragPath, dropPath, position = "after")`          | reorder an item within or across arrays; the primitive behind drag-and-drop lists. `position` is `"before"` or `"after"`; dropping into a descendant of the dragged item throws |

Two caveats on `setPathElement`:

* It **mutates** the object you pass and returns the *parent* node, not the root.
* With the default `deleteNull`, writing `null` or `undefined` **deletes** the key instead of storing an empty value. This is intentional and it is what makes clearing a field remove it from the record, but it will surprise you if you expect a null.

***

## Shaping objects

| Method          | Signature                         | Notes                                                                                                        |
| --------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `deepMerge`     | `(obj1, obj2, copyFirst = false)` | `obj2` wins. Arrays are replaced, not merged                                                                 |
| `flattenObj`    | `(obj, parent = "", res = {})`    | `{a:{b:1}}` → `{"a.b": 1}` plus type markers so it can be rebuilt                                            |
| `simpleFlatten` | `(obj, parent = "", res = {})`    | the same, without the markers                                                                                |
| `unflattenObj`  | `(obj, depth = 1, res = {})`      | inverse of `flattenObj`. Needs the markers to restore arrays; skips `_`-prefixed keys and drops empty values |
| `upperCase`     | `(name)`                          | null-safe                                                                                                    |

`deepMerge` mutates its first argument unless you pass `copyFirst: true`. **Always pass `copyFirst: true` when merging into something you did not create.** Configuration objects handed to you in props are shared.

`objectDiff` still exists but is deprecated and logs a warning on every call. Don't use it in new code.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.rierino.com/design/pro-code/modules/object-utilities.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
