Skip to content
Eugene Lazutkin edited this page Jul 19, 2026 · 7 revisions

This module contains simple utilities to work with embedded objects using paths.

path.js

Legend for tables
  • API
    • object — an object to work with.
    • path — a path to a nested object. It can be one of the following:
      • string — a path to a nested object separated by delimiter.
      • array — an array of names as strings, symbols, or integers.
    • delimiter — a string that separates names in path. Defaults to '.'.
      • It can be set to any value accepted by String.prototype.split(): a string, a regular expression, or a special object with a [Symbol.split] method.
    • defaultValue — a default value to return if path is not found. Defaults to undefined.
      • It can be set to any value. Usually it represents some default value, but it can represent a special "missing" or "incorrect" value. For example, it can be set to a unique Symbol() so the returned value can be checked in the case of failure.

Objects indexed by path can be any type of non-null objects, including arrays, and functions. Other values do not support indexing.

The following utilities are available:

Function Return value Description
get(object, path, {delimiter, defaultValue}) value Get value from a nested object by path.
has(object, path, {delimiter}) boolean Check that every segment of the path exists.
set(object, path, value, {delimiter, defaultValue}) value Set value in a nested object by path.
forceSet(object, path, value, {delimiter}) value Set value in a nested object by path creating/replacing missing or incorrect objects.
remove(object, path, {delimiter, defaultValue}) value Remove value from a nested object by path and return the removed value.

In case of failure to reach a value, defaultValue is returned. Otherwise, get() returns the requested value, set() returns the previous value at the path, and remove() returns the removed value.

has() answers what get() cannot: it distinguishes a missing path from a path that holds undefined. An empty path refers to the object itself and returns true.

set() creates the final property if it is missing, but intermediate path segments must already exist — use forceSet() to create them as needed.

forceSet() is similar to set() but it creates missing or incorrect objects. If the root object is not suitable to create sub-objects, forceSet() throws an error. It will throw in the case of an empty path. It returns the previous value at the path. When replacing objects, forceSet() will overwrite existing properties. It uses {} as missing objects.

Examples

get() and set():

import {get, has, set} from 'meta-toolkit/path.js';

const object = {a: {b: {c: 1}}};

get(object, 'a.b.c'); // 1
get(object, 'a.b'); // {c: 1}
get(object, 'a.d'); // undefined

has(object, 'a.b.c'); // true
has(object, 'a.d'); // false

get(object, 'a.d', {delimiter: '.', defaultValue: NaN}); // NaN
get(object, 'a/b/c', {delimiter: '/'}); // 1
get(object, ['a', 'b', 'c']); // 1

set(object, 'a.b.c', 2);
set(object, 'a.b.d', 3);

const key = Symbol();
object[key] = {};
set(object, [key, 'x'], 4);

const array = [1, 2, 3];

set(array, '1', {a: 1}); // array = [1, {a: 1}, 3]
get(array, '1.a'); // 1

forceSet() and remove():

import {forceSet, remove} from 'meta-toolkit/path.js';

const object = {};

forceSet(object, 'a.b.c', 1); // object = {a: {b: {c: 1}}}
forceSet(object, 'a.b.d', 2); // object = {a: {b: {c: 1, d: 2}}}
forceSet(object, 'b', 3); // object = {a: {b: {c: 1, d: 2}}, b: 3}
forceSet(object, 'b.c', 4); // object = {a: {b: {c: 1, d: 2}}, b: {c: 4}}

remove(object, 'a.b'); // object = {a: {}, b: {c: 4}}
remove(object, 'b.c'); // object = {a: {}, b: {}}
remove(object, 'a'); // object = {b: {}}

Path safety

get(), set(), forceSet(), and remove() walk user-supplied keys without sanitizing magic property names (__proto__, constructor, prototype). If your application passes externally-sourced paths (e.g., from HTTP requests, configuration files, or other untrusted input) directly to these functions, validate them at the application boundary first — the library does not. The trust boundary is the caller; library users are responsible for input sanitization.

Exports

All functions are exported by their names. There is no default export.

Clone this wiki locally