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 🙏

© 2026 – Pkg Stats / Ryan Hefner

jsonway

v0.4.0

Published

JSONway - object value getter & setter from path strings

Readme

JSONway

Find and filter nested values from JSON using JSONway's concise syntax, including conditional expressions. Same syntax also available as a setter path, and other useful functions to use with deeply nested JSON values.

Install

npm install jsonway

Usage

import JSONway from 'jsonway'

const myObject = {
  aa: { cc: { ff: 42, gg: true }, dd: 'value' },
  bb: [ { ff: 10 }, { ff: -5, gg: 'another' } ]
}

const result = JSONway.get(myObject, '**.ff(>=10)')
// [ 42, 10 ]

const tableQuery = `[{
  ff: bb[*].ff,
  aa.cc.ff,
  aa.dd,
}]
`
const table = JSONway.get(myObject, tableQuery)
// [
//   { ff: 10, 'aa.dd': 'value', 'aa.cc.ff': 42 },
//   { ff: -5, 'aa.dd': 'value', 'aa.cc.ff': 42 }
// ]

JSONway.set(table, '[*].gg', 'yes')
// [
//   { ff: 10, 'aa.dd': 'value', 'aa.cc.ff': 42, gg: 'yes' },
//   { ff: -5, 'aa.dd': 'value', 'aa.cc.ff': 42, gg: 'yes' }
// ]

Syntax

In general spaces and new lines are ignored and trimmed in the syntax, so that especially long paths don't need to be crammed into a one-liner.

Overview

  • a.b.c a value from nested objects.
  • a[].b all the b properties within a list of objects.
  • a[].b[].c all values of c as a flat list.
  • a[#] unique values of list a.
  • a[#].b unique values of b.
  • a[:].b[:].c a list of lists of values of c (keeping structure).
  • a[].b(>10) all b values that are larger than 10.
  • a[](b > 10 || c != 'foo').b all b values where c also is not "foo".
  • a[0] first value from list a.
  • a[-1] last value.
  • a[-2:] last 2 values.
  • a[:3] first 3 values.
  • a[1:6] first 5 values while skipping the first.
  • a[0,2,-1] first, third, and last values in a list.
  • a.**.c all c values regardless where they are nested under a.
  • **.(>10) all numbers anywhere in the JSON that are larger than 10.
  • { a.b, d.e } object with keys matching their own query results.
  • { myKey: a[].b } keys can be renamed similarly like in JSON or JavaScript.
  • [{ a[*].b, c.d }] list of objects expanded by values of b.

When a key name in a path needs to be escaped, it can be done like a[b.c].d or a['b[]'].c.

Expressions

  • (?) value isn't undefined.
  • (<0) value is smaller than 0.
  • (a >= 5) where a is larger or equal to 5.
  • (a ~= 'foo' && a != ['foo', 'foobar']) where a contains "foo" and isn't "foo" nor "foobar".
  • (status? && (status = [401, 403] || status >= 500)) parenthesis can be used, too.

Pipe modifiers

  • a[ # | size ].b amount of unique b values within a list.
  • a[|> max].b largest b value.
  • a.b.c |> split._.7 split value c by underscore _, and return its 8th part.
  • a[ |> sort.reverse[0] ] sort in descending order and take the first value.
  • min,, sum, floor, ceil, round, trunc, avg, also supported.

Examples

Return a list of objects from a Babel AST of the test file.

program.body[]
  .expression(callee.name = 'describe')
  .arguments[](type = 'ArrowFunctionExpression')
  .body.body[](
    expression.callee.name = 'it' &&
    expression.arguments[0].type = [
      'TemplateLiteral',
      'StringLiteral',
    ]
  )
  .expression.arguments{
    path: [0].value,
    path: [0].quasis[0].value.cooked,
    vars: [1].body.body[](type = 'VariableDeclaration')
          .declarations[0].id.name,
  }

Which returns something like this from Babel parsed test/setter.js file:

[
  ...
  { path: 'a.b', vars: [ 'out' ] },
  { path: 'a.b.c', vars: [ 'object', 'out' ] },
  { path: 'a[0]', vars: [ 'object', 'out' ] },
  ...
]

Syntax allows us to go through step by step the JSON file, filtering further as we go more nested. Filter conditions always get the current value of list or object as the context, which reduces repeated syntax.


Another example, where a nested list of objects is expanded into a simpler list of objects:

[{
  bb[*].dd,
  bb[].ee[*].dd: bb[].ee[*].dd (!='dd13'),
  bb[].ee[].hh[].ii.dd,
  bb[].ee[].hh[].dd,
  bb[].cc,
  aa,
}]

Returns list of objects separately for each value found with paths having [*] list expansion in them. Values above of the expanded paths are duplicated, while values for even further nested paths are aggregated.

[
  ...
  {
    'aa': 'aa1',
    'bb[0].dd': 'dd1',
    'bb[0].ee[0].dd': 'dd7',
    'bb[0].ee[].hh[].dd': [ 'dd8', 'dd10' ],
    'bb[0].ee[].hh[].ii.dd': [ 'dd9', 'dd11' ]
    'bb[0].cc': 'cc1',
  },
  ...
]

Other methods

JSONway exposes following methods:

{
  analyze,
  calculateExpression,
  expand,
  expandAll,
  flatten,
  get,
  has,
  parse,
  parseExpression,
  set,
  stringify
}

For further explanations check documentation folder. For more examples check the test folder.

Why (yet another) JSON query language?

It's true that there are already many popular JSON query languages like JSONPath, JSONata, and JMESPath. I wanted to create my own syntax and language from scratch that was slightly different, while indeed inspired by those and many others.

Goals and guiding principles for JSONway have been to have concise but safety-restricted syntax, imitating JavaScript syntax and logic when possible, and zero dependencies. Creating table-like lists of objects from complex JSON structures, has been one of the main use cases JSONway has been trying to solve.

Writing your own parser and interpreter for your own query language are educational already on their own, and I would strongly recommend others to do the same. Deciding on a syntax and available capabilities for the language depends heavily on the use cases you have in mind, and I don't believe we will have "one query language to rule them all" in the future, either.

Hopefully JSONway can be the query language for your needs!


MIT licensed.