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

jsonpath-engine

v1.0.0

Published

TypeScript-first, RFC 9535-compliant JSONPath query engine.

Readme

JSONPath is a small query language for JSON, in the same spirit as XPath for XML or CSS selectors for the DOM. jsonpath-engine implements RFC 9535 (Query Expressions for JSON), the IETF standard that defines JSONPath's syntax, semantics, and well-typedness rules.

Installation

npm install jsonpath-engine
# or
pnpm add jsonpath-engine
# or
yarn add jsonpath-engine

Basic usage

import { query, paths, nodes, first, exists } from 'jsonpath-engine'

const document = {
  store: {
    book: [
      { category: 'reference', author: 'Nigel Rees', title: 'Sayings of the Century', price: 8.95 },
      { category: 'fiction', author: 'Evelyn Waugh', title: 'Sword of Honour', price: 12.99 },
      { category: 'fiction', author: 'Herman Melville', title: 'Moby Dick', price: 8.99 },
    ],
    bicycle: { color: 'red', price: 19.95 },
  },
}

query(document, '$.store.book[*].title')
// ["Sayings of the Century", "Sword of Honour", "Moby Dick"]

query(document, '$.store.book[[email protected] < 10].title')
// ["Sayings of the Century", "Moby Dick"]

paths(document, '$..price')
// ["$['store']['book'][0]['price']", "$['store']['book'][1]['price']", ...]

nodes(document, '$.store.book[0]')
// [{ value: { category: "reference", ... }, path: "$['store']['book'][0]" }]

first(document, '$.store.book[0].title')
// "Sayings of the Century"

exists(document, "$.store.book[[email protected] == 'Nigel Rees']")
// true

Compile once, run many

compile parses a query and runs the well-typedness check up front, so syntax and type errors raise at compile time rather than every evaluation. The result exposes the same five operations as the one-shot helpers and can be reused across documents.

import { compile } from 'jsonpath-engine'

const cheapBookTitles = compile('$.store.book[[email protected] < 10].title')

for (const document of largeStream) {
  console.log(cheapBookTitles.query(document))
}

cheapBookTitles.source returns the original query string for logging.

Custom functions

The standard functions are pre-registered. Define your own with defineFunction, and the parameter and return types are inferred from the declared argTypes and resultType.

import { defineFunction, registerFunction, LogicalTrue, LogicalFalse, query } from 'jsonpath-engine'

const startsWith = defineFunction({
  argTypes: ['ValueType', 'ValueType'] as const,
  resultType: 'LogicalType',
  evaluate(subject, prefix) {
    // subject and prefix are typed as ValueType, no manual narrowing needed
    if (typeof subject !== 'string' || typeof prefix !== 'string') {
      return LogicalFalse
    }
    return subject.startsWith(prefix) ? LogicalTrue : LogicalFalse
  },
})

registerFunction('starts_with', startsWith)

query(users, "$[?starts_with(@.name, 'A')]")

Function names follow the RFC 9535 ABNF: a lowercase letter followed by lowercase letters, digits, and underscores. Standard names (length, count, value, match, search) are reserved.

JSONPath syntax

| Construct | Syntax | Example | | --------------------- | ------------------------ | ------------------------------------ | | Root identifier | $ | $ returns the whole document | | Member-name shorthand | .name | $.store.book | | Bracketed member name | ['name'] or ["name"] | $['store']['book'] | | Wildcard | * or .* | $.store.book[*] | | Index selector | [N] | $.store.book[0] | | Negative index | [-N] | $.store.book[-1] (last) | | Slice selector | [start:end:step] | $.store.book[0:2], $..book[::-1] | | Filter selector | [?expr] | $.store.book[[email protected] < 10] | | Descendant segment | .. | $..price, $..book[[email protected]] | | Multiple selectors | [a, b, c] | $['store']['book'][0, 2] | | Current node | @ | [[email protected] < 10] inside a filter |

Filter expression operators by precedence, highest first: comparison (< <= > >= == !=), logical not (!), logical and (&&), logical or (||). Parentheses force grouping.

The five standard functions, per RFC 9535 sections 2.4.4 through 2.4.8:

| Function | Signature | Notes | | ------------------------ | ------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | length(value) | ValueType -> ValueType | Unicode code-point count for strings, length for arrays, key count for objects. Nothing for other inputs. | | count(nodes) | NodesType -> ValueType | Size of a nodelist. | | value(nodes) | NodesType -> ValueType | The value of a singleton nodelist, or Nothing. | | match(value, pattern) | ValueType, ValueType -> LogicalType | Full-string i-regexp match per RFC 9485. | | search(value, pattern) | ValueType, ValueType -> LogicalType | Substring i-regexp match per RFC 9485. |

Errors

Three error classes, each extending the native parent so existing instanceof SyntaxError or instanceof TypeError checks keep working.

class JsonPathSyntaxError extends SyntaxError {
  readonly query: string
  readonly start: number
  readonly end: number
  readonly code: JsonPathSyntaxErrorCode
}

class JsonPathTypeError extends TypeError {
  readonly query: string
  readonly start: number
  readonly end: number
  readonly code: JsonPathTypeErrorCode
}

class JsonPathFunctionError extends Error {
  readonly functionName: string
  readonly code: JsonPathFunctionErrorCode
}

Each error has a stable string code for programmatic dispatch. formatJsonPathError renders a multi-line caret view of the offending span.

try {
  compile('$.foo[?(')
} catch (caught) {
  if (caught instanceof JsonPathSyntaxError) {
    console.error(formatJsonPathError(caught))
    // JsonPathSyntaxError [empty-filter]: ...
    //   1 | $.foo[?(
    //     |        ^
  }
}

API

Query helpers

function query(json: JsonValue, path: string): JsonValue[]
function paths(json: JsonValue, path: string): NormalizedPath[]
function nodes(json: JsonValue, path: string): JsonPathNode[]
function first(json: JsonValue, path: string): JsonValue | undefined
function exists(json: JsonValue, path: string): boolean

function compile(path: string): CompiledJsonPath
type CompiledJsonPath = {
  readonly source: string
  query(json: JsonValue): JsonValue[]
  paths(json: JsonValue): NormalizedPath[]
  nodes(json: JsonValue): JsonPathNode[]
  first(json: JsonValue): JsonValue | undefined
  exists(json: JsonValue): boolean
}

type JsonPathNode = {
  readonly value: JsonValue
  readonly path: NormalizedPath
}

type Nodelist = readonly JsonPathNode[]
type NormalizedPath = string

Function registry

function defineFunction<Args, Result>(extension: {
  argTypes: Args
  resultType: Result
  evaluate(...args): RuntimeOf<Result>
}): JsonPathFunctionExtension

function registerFunction(name: string, extension: JsonPathFunctionExtension): void
function unregisterFunction(name: string): boolean
function listFunctions(): readonly string[]

Runtime type system

The runtime types from RFC 9535 section 2.4.1, plus type guards and the nodelistToValue conversion from section 2.4.3.

const Nothing: unique symbol
const LogicalTrue: unique symbol
const LogicalFalse: unique symbol

function isNothing(value: JsonPathFunctionArg): boolean
function isLogicalTrue(value: JsonPathFunctionArg): boolean
function isLogicalFalse(value: JsonPathFunctionArg): boolean
function isNodesType(value: JsonPathFunctionArg): boolean
function nodelistToValue(nodes: NodesType): ValueType

License

MIT License © 2026-present Cong Nguyen