Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .eslintignore

This file was deleted.

9 changes: 0 additions & 9 deletions .eslintrc.js

This file was deleted.

42 changes: 42 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
name: Bug Report
about: Report a bug or unexpected behavior
title: ''
labels: bug
assignees: ''
---

## Description

A clear description of the bug.

## Steps to Reproduce

```javascript
import { query } from 'jsonpathly';

const data = {
// your test data
};

const result = query(data, '$.your.path');
console.log(result);
```

## Expected Behavior

What you expected to happen.

## Actual Behavior

What actually happened.

## Environment

- jsonpathly version:
- Node.js version:
- OS:

## Additional Context

Any other relevant information (RFC reference, related issues, etc.)
38 changes: 38 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
name: Feature Request
about: Suggest a new feature or enhancement
title: ''
labels: enhancement
assignees: ''
---

## Summary

A brief description of the feature.

## Use Case

Why is this feature needed? What problem does it solve?

## Proposed Solution

How should this feature work?

```javascript
// Example of desired API/behavior
import { query } from 'jsonpathly';

const result = query(data, '$.proposed.syntax');
```

## Alternatives Considered

Any alternative approaches you've considered.

## RFC Reference

If applicable, reference to RFC 9535 or other JSONPath specifications.

## Additional Context

Any other relevant information.
27 changes: 27 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Description

Brief description of the changes.

## Type of Change

- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation update

## Checklist

- [ ] I have read the [CONTRIBUTING](../CONTRIBUTING.md) guide
- [ ] My code follows the project's code style
- [ ] I have added tests that prove my fix/feature works
- [ ] All new and existing tests pass (`npm test`)
- [ ] I have updated the documentation if needed
- [ ] I have updated CHANGELOG.md if this is a user-facing change

## Related Issues

Fixes #(issue number)

## RFC 9535 Reference

If applicable, reference the relevant RFC 9535 section.
64 changes: 64 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: CI

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
test:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18, 20, 22]

steps:
- uses: actions/checkout@v4

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Run tests
run: npm test

- name: Run linter
run: npm run lint

coverage:
runs-on: ubuntu-latest
needs: test

steps:
- uses: actions/checkout@v4

- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Run coverage
run: npx c8 --reporter=text --reporter=lcov npm test

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage/lcov.info
fail_ci_if_error: false
43 changes: 43 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Publish to npm

on:
push:
tags:
- 'v*'

permissions:
id-token: write # Required for OIDC trusted publishing
contents: write # Required for GitHub release creation

jobs:
publish:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
registry-url: 'https://registry.npmjs.org'

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build

- name: Run tests
run: npm test

# No NPM_TOKEN needed - uses OIDC trusted publishing
# Provenance is automatic with trusted publishing
- name: Publish to npm
run: npm publish --access public

- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
62 changes: 62 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [3.0.0] - 2025-01-09

### Breaking Changes

- **Path format**: Changed from double quotes to single quotes per RFC 9535
- Before: `$["store"]["book"][0]`
- After: `$['store']['book'][0]`

### Added

- RFC 9535 compliant functions: `length()`, `count()`, `match()`, `search()`, `value()`
- I-Regexp validation for `match()` and `search()` patterns
- Filter expressions without parentheses: `$[?@.price > 10]`
- Empty nodelist comparison support
- Integer range validation (I-JSON bounds)
- Comprehensive JSDoc documentation for all public APIs

### Changed

- Replaced ANTLR4 parser with Peggy for smaller bundle size
- Replaced webpack with tsup for faster builds
- Zero runtime dependencies (removed fast-deep-equal)
- Modularized codebase (extracted comparators, functions)

### Fixed

- Nested filter expressions in boolean context (Issue #14)
- Filters on primitive arrays (Issue #12)

## [2.0.2] - 2024-XX-XX

### Fixed

- Incorrect module import

## [2.0.1] - 2024-XX-XX

### Fixed

- GitHub Actions cache version

## [2.0.0] - 2024-XX-XX

### Changed

- Updated ANTLR4 version
- NodeJS webpack config fix

[Unreleased]: https://github.com/atamano/jsonpathly/compare/v3.0.0...HEAD
[3.0.0]: https://github.com/atamano/jsonpathly/compare/v2.0.2...v3.0.0
[2.0.2]: https://github.com/atamano/jsonpathly/compare/v2.0.1...v2.0.2
[2.0.1]: https://github.com/atamano/jsonpathly/compare/v2.0.0...v2.0.1
[2.0.0]: https://github.com/atamano/jsonpathly/releases/tag/v2.0.0
97 changes: 97 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

jsonpathly is a secure, eval-free TypeScript library for querying JSON documents using JSONPath expressions. It is RFC 9535 compliant and uses Peggy for parsing (zero runtime dependencies).

## Common Commands

```bash
# Run all tests
npm test

# Run a single test file
npx mocha --require ts-node/register --timeout 60000 --exit tests/<filename>.ts

# Run tests with coverage
npx c8 npm test

# Build (generates dist/ with cjs and esm)
npm run build

# Lint
npm run lint

# Format code
npm run format

# Regenerate parser (after modifying jsonpath.peggy)
npm run gen

# Release (bumps version, commits, tags, pushes - CI publishes to npm)
npm run release:patch # 3.0.0 -> 3.0.1
npm run release:minor # 3.0.0 -> 3.1.0
npm run release:major # 3.0.0 -> 4.0.0
```

## Architecture

### Entry Point
- `src/index.ts` - Exports the public API: `query`, `paths`, `parse`, `stringify`, `JSONPathSyntaxError`

### Parser Layer (`src/parser/`)
- `jsonpath.peggy` - Peggy grammar defining JSONPath syntax (RFC 9535 compliant)
- `generated/parser.js` - Auto-generated parser (do not edit manually)
- `parse.ts` - Converts JSONPath string to AST using Peggy parser
- `types.ts` - TypeScript types for the AST nodes (Root, Subscript, FilterExpression, FunctionCall, etc.)
- `stringify.ts` - Converts AST back to JSONPath string (with RFC 9535 normalized escaping)
- `errors.ts` - Custom syntax error class

### Handler Layer (`src/handler/`)
- `Handler.ts` - Core query engine that traverses JSON using the AST
- `query.ts` - Public `query()` function wrapping Handler
- `paths.ts` - Public `paths()` function returning matched paths
- `functions.ts` - RFC 9535 function implementations (`length`, `count`, `match`, `search`, `value`)
- `comparators.ts` - Filter comparison operators (`==`, `!=`, `<`, `<=`, `>`, `>=`, `in`, etc.)
- `helper.ts` - Type guards and utility functions (`isEqual`, `isArray`, `isPlainObject`)

### Key Design Patterns
- **AST-based evaluation**: JSONPath is parsed into a typed AST (`Root` -> `Subscript` chain), then the Handler walks both the AST and JSON simultaneously
- **ValuePath tracking**: Handler maintains both values and their JSONPath locations throughout traversal
- **Indefinite results**: Operations like `..` or `*` return arrays, tracked via `isIndefinite` flag
- **I-Regexp validation**: `match()` and `search()` validate patterns against RFC 9485 I-Regexp subset

## Build Output

tsup builds to `dist/`:
- `index.cjs` - CommonJS build
- `index.mjs` - ES Module build
- `index.d.ts` / `index.d.mts` - Type declarations

Zero runtime dependencies - Peggy generates a standalone parser at build time.

## Testing

Test files in `tests/`:
- `query.test.ts` - Core query functionality
- `paths.test.ts` - Path output formatting
- `parse.test.ts` - Parser and stringify round-trips
- `rfc9535-compliance.test.ts` - RFC 9535 specific tests
- `consensus.test.ts` - Cross-implementation compatibility (uses `data/consensus-tests.ts`)
- `extensions.test.ts` - jsonpathly-specific extensions (in, nin, subsetof, etc.)
- `api.test.ts` - Public API contracts
- `module-resolution.test.ts` - ESM/CJS build verification

**Note:** ~70 consensus tests are intentionally skipped (pending). These represent:
- RFC 9535 semantic differences (jsonpathly follows the RFC strictly)
- Ambiguous syntax with no standard behavior across implementations

## RFC 9535 Compliance

jsonpathly is fully RFC 9535 compliant:
- Normalized path format uses single quotes: `$['key']` not `$["key"]`
- I-Regexp validation (RFC 9485) for `match()` and `search()`
- I-JSON integer range validation
- All 5 function extensions: `length`, `count`, `match`, `search`, `value`
Loading