npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@tsmx/json-traverse

v1.0.7

Published

Traverse and manipulate JSON objects.

Downloads

2,849

Readme

@tsmx/json-traverse

License: MIT npm (scoped) node-current (scoped) Build Status Coverage Status

Traverse and manipulate JSON objects.

Usage

Basic usage

const jt = require('@tsmx/json-traverse');

const callbacks = {
    processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => { 
            /* your logic here */ 
        },
    enterLevel: (level, path) => { 
            /* your logic here */ 
        },
    exitLevel: (level, path) => { 
            /* your logic here */ 
        }
};

var obj = { /* your JSON object */ };

jt.traverse(obj, callbacks);

Example 1: print out a simple object

var simpleObj = {
    MyValue: 'test',
    OtherValue: 'zzz',
    NumberValue: 311,
    MyArray: [1, 2, 3, 50, 60, 70]
};

const callbacks = {
    processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => { 
        console.log(level + ' ' + (path.length > 0 ? (path.join('.') + '.') : '') + key + ' = ' + value); 
    }
};

const jt = require('@tsmx/json-traverse');

jt.traverse(simpleObj, callbacks);
// 0 MyValue = test
// 0 OtherValue = xxx
// 0 NumberValue = 311
// 0 MyArray._0 = 1
// 0 MyArray._1 = 2
// 0 MyArray._2 = 3
// 0 MyArray._3 = 50
// 0 MyArray._4 = 60
// 0 MyArray._5 = 70

// flat array-mode: flattenArray = true (arrays are treated as one value)
jt.traverse(simpleObj, callbacks, true);
// 0 MyValue = test
// 0 OtherValue = xxx
// 0 NumberValue = 311
// 0 MyArray = 1,2,3,50,60,70

Example 2: change values of an object

var simpleObj = {
    MyValue: 'test',
    OtherValue: 'zzz',
    NumberValue: 311,
    MyArray: [1, 2, 3, 50, 60, 70]
};

const callbacks = {
    processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => { 
        // change values of properties starting with 'My' and
        // multiply all numeric array values greater then 50 by 100
        if (key.startsWith('My')) {
            cbSetValue('MyNew-' + value);
        }
        if (isArrayElement && parseInt(value) > 50) {
            cbSetValue(100 * parseInt(value));
        }
    }
};

const jt = require('@tsmx/json-traverse');

jt.traverse(simpleObj, callbacks);

// {
//   MyValue : "MyNew-test",
//   OtherValue: "xxx",
//   NumberValue: 311,
//   MyArray: [ 1, 2, 3, 50, 6000, 7000 ]
// }

Example 3: convert a more complex object to a collapsible HTML list

var htmlObj = {
    MyArray: [0, 0],
    ArrayInArray: [0, 1, ['two', 'three', [4, 5, 6]]],
    MyNumber: 123,
    MyString: 'test',
    Child: {
        ChildVal: 1,
        SubChild: {
            SubChildVal: 777
        },
        ChildArray: [1, 2, 66, 9, 900]
    },
    TrailingValue: 'testtesttest'
}

const callbacksHtmlList = {
    processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => {
        if (isObjectRoot) {
            console.log(('  ').repeat(level) + ' <li class=\"caret\">Key: ' + key + '</li>')
        }
        else {
            console.log(('  ').repeat(level) + ' <li>Key: ' + key + ', Value: ' + value + '</li>')
        };
    },
    enterLevel: (level, path) => {
        if (level == 0) {
            console.log('<ul>');
        }
        else {
            console.log(('  ').repeat(level) + '<ul class=\"nested\">');
        };
    },
    exitLevel: (level, path) => { console.log(('  ').repeat(level) + '</ul>'); }
};

const jt = require('@tsmx/json-traverse');

jt.traverse(htmlObj, callbacksHtmlList, true);

// <ul>
//  <li>Key: MyArray, Value: 0,0</li>
//  <li>Key: ArrayInArray, Value: 0,1,two,three,4,5,6</li>
//  <li>Key: MyNumber, Value: 123</li>
//  <li>Key: MyString, Value: test</li>
//  <li class="caret">Key: Child</li>
//   <ul class="nested">
//    <li>Key: ChildVal, Value: 1</li>
//    <li class="caret">Key: SubChild</li>
//     <ul class="nested">
//      <li>Key: SubChildVal, Value: 777</li>
//     </ul>
//    <li>Key: ChildArray, Value: 1,2,66,9,900</li>
//   </ul>
//  <li>Key: TrailingValue, Value: testtesttest</li>
// </ul>

Key-features

  • Define your callbacks for the following events:
    • processValue: processing a traversed value
    • enterLevel: entering a new nesting level
    • exitLevel: leaving nesting level
  • For every inspected value you will get rich meta-data
    • key name
    • level of nesting
    • isObjectRoot flag to indicate if it's an object root (root of a nested object)
    • isArrayElement flag to indicate if it's an array item
    • full path to the key as an array of path elements
  • Provides cbSetValue function to change any value in-place (directly in the traversed object)
  • Supports deep inspection of
    • Subobjects
    • Arrays
    • Arrays-in-Arrays
    • Subobjects-in-Arrays
  • Optional array flattening (treat arrays as flat values)

API

traverse(obj, callbacks = null, flattenArray = false)

Traverse the obj and apply the defined callbacks while traversing.

obj

Type: Object

The object to be traversed.

callbacks

Type: Object Default: null

An Object containing the callback functions that should be applied while traversing obj. Every callback is optional. The expected form is:

callbacks = {
    processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => { 
            /* your logic here */ 
        },
    enterLevel: (level, path) => { 
            /* your logic here */ 
        },
    exitLevel: (level, path) => { 
            /* your logic here */ 
        }
};
processValue(key, value, level, path, isObjectRoot, isArrayElement, cbSetValue)

Defined callback function that is executed on each value when traversing the object. Receives the following input parameters:

key

Type: String

The key of the current value that is processed. If an array is deep-inspected the key for each processed item is _ + Index (_0, _1, _2,...).

value

Type: String

The actual value for key.

level

Type: Number

The nesting level. 0 indicates the first level.

path

Type: Array

An array containing all keys that where passed to reach the current key/value pair. Example:

{
    child: {
        subchild: {
            myvalue: 123;
        }
    }
}

When processing the value 123 with key myvalue, path would be ['child', 'subchild' ].

For deep-inspected arrays the path would contain the name of the array itself whereas the key would be the index of the processed value. Example:

{
    child: {
        subchild: {
            myvalues: [1, 2, 3]
        }
    }
}

When processing the array the keys would be _0, _1 and _2 and the path would always be ['child', 'subchild', 'myvalues'].

isObjectRoot

Type: Boolean

true if the currently processed key is the root of another sub-object. In our example:

{
    child: {
        subchild: {
            myvalue: 123;
        }
    }
}

isObjectRoot would be true for the keys child and subchild.

isArrayElement

Type: Boolean

true if the currently processed key is an item of an array.

cbSetValue(newValue)

Type: Function

Callback function receiving the newValue that should replace the currently traversed value.

Note: Setting a new value directly changes the traversed object! So if you need the original later on be sure to create a copy of the object first.

enterLevel(level, path)

Defined callback function that is executed on entering a new nesting level when traversing the object. Receives the following input parameters:

level

Type: Number

0-based index of the nesting level that is entered.

path

Type: Array

An array containing all keys that where passed to reach the current level that is entered.

exitLevel(level, path)

Defined callback function that is executed on leaving a nesting level when traversing the object. Receives the following input parameters:

level

Type: Number

0-based index of the nesting level that is exited.

path

Type: Array

An array containing all keys that where passed to reach the current level that is exited.

flattenArray

Type: Boolean Default: false

If set to true arrays will not be iterated but treated as one single value. The default is false, where arrays are iterated and each entry is processed separately including deep-inspection, e.g. if the entry is an object or another array.