Skip to content

Commit

Permalink
Renamed the package to json_path
Browse files Browse the repository at this point in the history
  • Loading branch information
f3ath committed Jul 29, 2020
1 parent fd745c3 commit 3e0cff4
Show file tree
Hide file tree
Showing 16 changed files with 163 additions and 92 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
## [Unreleased]
## [0.0.0+dev.2] - 2020-07-28
### Added
- Recursive selector
- Wildcard selector

## [0.0.0+dev.1] - 2020-07-27
### Added
- Tokenizer and AST
Expand All @@ -8,5 +13,6 @@
### Added
- Basic design draft

[Unreleased]: https://github.com/f3ath/jessie/compare/0.0.0+dev.1...HEAD
[Unreleased]: https://github.com/f3ath/jessie/compare/0.0.0+dev.2...HEAD
[0.0.0+dev.2]: https://github.com/f3ath/jessie/compare/0.0.0+dev.1...0.0.0+dev.2
[0.0.0+dev.1]: https://github.com/f3ath/jessie/compare/0.0.0+dev.0...0.0.0+dev.1
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# [JSONPath] for Dart
Jessie is a work-in-progress. Expect the API to change often. Feel free to join.
**Warning!** This is a work-in-progress. Expect the API to change often. Also, feel free to join.

## Roadmap
- [x] Basic selectors: fields, indices
Expand Down
56 changes: 56 additions & 0 deletions example/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import 'dart:convert';

import 'package:json_path/json_path.dart';

void main() {
final json = jsonDecode('''
{
"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",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
}
}
''');

/// The following code will print:
///
/// $['store']['book'][0]['price']: 8.95
/// $['store']['book'][1]['price']: 12.99
/// $['store']['book'][2]['price']: 8.99
/// $['store']['book'][3]['price']: 22.99
/// $['store']['bicycle']['price']: 19.95
JsonPath(r'$..price')
.select(json)
.map((result) => '${result.path}:\t${result.value}')
.forEach(print);
}
5 changes: 0 additions & 5 deletions lib/jessie.dart

This file was deleted.

5 changes: 5 additions & 0 deletions lib/json_path.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// JSONPath for Dart
library json_path;

export 'package:json_path/src/json_path.dart';
export 'package:json_path/src/result.dart';
12 changes: 6 additions & 6 deletions lib/src/json_path.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import 'package:jessie/src/ast.dart';
import 'package:jessie/src/selector/selector.dart';
import 'package:jessie/src/selector/root.dart';
import 'package:jessie/src/result.dart';
import 'package:jessie/src/state.dart';
import 'package:jessie/src/tokenize.dart';
import 'package:json_path/src/ast.dart';
import 'package:json_path/src/result.dart';
import 'package:json_path/src/selector/root.dart';
import 'package:json_path/src/selector/selector.dart';
import 'package:json_path/src/state.dart';
import 'package:json_path/src/tokenize.dart';

class JsonPath {
factory JsonPath(String expression) {
Expand Down
4 changes: 2 additions & 2 deletions lib/src/selector/all_in_array.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:jessie/src/selector/selector.dart';
import 'package:jessie/src/result.dart';
import 'package:json_path/src/result.dart';
import 'package:json_path/src/selector/selector.dart';

class AllInArray extends Selector {
@override
Expand Down
6 changes: 3 additions & 3 deletions lib/src/selector/all_values.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:jessie/src/quote.dart';
import 'package:jessie/src/result.dart';
import 'package:jessie/src/selector/selector.dart';
import 'package:json_path/src/quote.dart';
import 'package:json_path/src/result.dart';
import 'package:json_path/src/selector/selector.dart';

class AllValues extends Selector {
@override
Expand Down
6 changes: 3 additions & 3 deletions lib/src/selector/field.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:jessie/src/quote.dart';
import 'package:jessie/src/result.dart';
import 'package:jessie/src/selector/selector.dart';
import 'package:json_path/src/quote.dart';
import 'package:json_path/src/result.dart';
import 'package:json_path/src/selector/selector.dart';

class Field extends Selector {
Field(this.name);
Expand Down
4 changes: 2 additions & 2 deletions lib/src/selector/index.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:jessie/src/selector/selector.dart';
import 'package:jessie/src/result.dart';
import 'package:json_path/src/result.dart';
import 'package:json_path/src/selector/selector.dart';

class Index extends Selector {
Index(this.index);
Expand Down
6 changes: 3 additions & 3 deletions lib/src/selector/recursive.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:jessie/src/quote.dart';
import 'package:jessie/src/result.dart';
import 'package:jessie/src/selector/selector.dart';
import 'package:json_path/src/quote.dart';
import 'package:json_path/src/result.dart';
import 'package:json_path/src/selector/selector.dart';

class Recursive extends Selector {
@override
Expand Down
4 changes: 2 additions & 2 deletions lib/src/selector/root.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:jessie/src/selector/selector.dart';
import 'package:jessie/src/result.dart';
import 'package:json_path/src/result.dart';
import 'package:json_path/src/selector/selector.dart';

class Root extends Selector {
const Root();
Expand Down
6 changes: 3 additions & 3 deletions lib/src/selector/selector.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:jessie/src/result.dart';
import 'package:jessie/src/selector/all_values.dart';
import 'package:jessie/src/selector/recursive.dart';
import 'package:json_path/src/result.dart';
import 'package:json_path/src/selector/all_values.dart';
import 'package:json_path/src/selector/recursive.dart';

/// Converts a set of results into a set of results
abstract class Selector {
Expand Down
48 changes: 22 additions & 26 deletions lib/src/state.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import 'package:jessie/src/ast.dart';
import 'package:jessie/src/selector/all_in_array.dart';
import 'package:jessie/src/selector/all_values.dart';
import 'package:jessie/src/selector/field.dart';
import 'package:jessie/src/selector/index.dart';
import 'package:jessie/src/selector/recursive.dart';
import 'package:jessie/src/selector/selector.dart';
import 'package:json_path/src/ast.dart';
import 'package:json_path/src/selector/all_in_array.dart';
import 'package:json_path/src/selector/all_values.dart';
import 'package:json_path/src/selector/field.dart';
import 'package:json_path/src/selector/index.dart';
import 'package:json_path/src/selector/recursive.dart';
import 'package:json_path/src/selector/selector.dart';

/// AST parser state
abstract class State {
Expand All @@ -24,28 +24,24 @@ class Ready implements State {

@override
State process(Node node) {
if (node.value == '[') {
return Ready(selector.then(_brackets(node.children)));
switch (node.value) {
case '[':
return Ready(selector.then(_bracketExpression(node.children)));
case '.':
return AwaitingField(selector);
case '..':
return Ready(selector.then(Recursive()));
case '*':
return Ready(selector.then(AllValues()));
default:
return Ready(selector.then(Field(node.value)));
}
if (node.value == '.') {
return AwaitingField(selector);
}
if (node.value == '..') {
return Ready(selector.then(Recursive()));
}
if (node.value == '*') {
return Ready(selector.then(AllValues()));
}

throw StateError('Got ${node.value} in $this');
}

Selector _brackets(List<Node> nodes) {
if (nodes.length == 1) {
final node = nodes.single;
if (node.value == '*') return AllInArray();
if (node.isNumber) return Index(int.parse(nodes.first.value));
}
Selector _bracketExpression(List<Node> nodes) {
final node = nodes.single;
if (node.value == '*') return AllInArray();
if (node.isNumber) return Index(int.parse(nodes.first.value));
throw StateError('Unexpected bracket expression');
}
}
Expand Down
6 changes: 3 additions & 3 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: jessie
version: 0.0.0+dev.1
description: JSONPath for Dart
name: json_path
version: 0.0.0+dev.2
description: JSONPath for Dart. JSONPath is XPath for JSON. It is a path in a JSON document.
homepage: "https://github.com/f3ath/jessie"

dev_dependencies:
Expand Down
77 changes: 45 additions & 32 deletions test/json_path_test.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dart:convert';
import 'dart:io';

import 'package:jessie/jessie.dart';
import 'package:json_path/json_path.dart';
import 'package:test/test.dart';

void main() {
Expand All @@ -27,33 +27,17 @@ void main() {
expect(store.select(json).single.value, json['store']);
expect(store.select(json).single.path, r"$['store']");
});
});

test('Path with an index', () {
final firstBookTitle = JsonPath(r'$.store.book[0].title');
expect(firstBookTitle.toString(), r"$['store']['book'][0]['title']");
expect(
firstBookTitle.select(json).single.value, 'Sayings of the Century');
expect(firstBookTitle.select(json).single.path,
r"$['store']['book'][0]['title']");
});

test('All in array', () {
final allBooksInStore = JsonPath(r'$.store.book[*]');
expect(allBooksInStore.toString(), r"$['store']['book'][*]");
expect(allBooksInStore.select(json).length, 4);
expect(
allBooksInStore.select(json).first.value, json['store']['book'][0]);
expect(allBooksInStore.select(json).first.path, r"$['store']['book'][0]");
expect(allBooksInStore.select(json).last.value, json['store']['book'][3]);
expect(allBooksInStore.select(json).last.path, r"$['store']['book'][3]");
});

test('All values', () {
group('Wildcards', () {
test('All in root', () {
final allInRoot = JsonPath(r'$.*');
expect(allInRoot.toString(), r'$.*');
expect(allInRoot.select(json).single.value, json['store']);
expect(allInRoot.select(json).single.path, r"$['store']");
});

test('All in store', () {
final allInStore = JsonPath(r'$.store.*');
expect(allInStore.toString(), r"$['store'].*");
expect(allInStore.select(json).length, 2);
Expand All @@ -62,7 +46,9 @@ void main() {
expect(allInStore.select(json).last.value, json['store']['bicycle']);
expect(allInStore.select(json).last.path, r"$['store']['bicycle']");
});
});

group('Recursion', () {
test('Recursive', () {
final allNode = JsonPath(r'$..');
expect(allNode.toString(), r'$..');
Expand All @@ -73,16 +59,43 @@ void main() {
expect(allNode.select(json).last.path, r"$['store']['bicycle']");
});

test('Recursive with all fields', () {
final allValues = JsonPath(r'$..*');
expect(allValues.toString(), r'$..*');
expect(allValues.select(json).length, 27);
expect(allValues.select(json).first.value, json['store']);
expect(allValues.select(json).first.path, r"$['store']");
expect(
allValues.select(json).last.value, json['store']['bicycle']['price']);
expect(
allValues.select(json).last.path, r"$['store']['bicycle']['price']");
test('Recursive with all values', () {
final path = JsonPath(r'$..*');
expect(path.toString(), r'$..*');
expect(path.select(json).length, 27);
expect(path.select(json).first.value, json['store']);
expect(path.select(json).first.path, r"$['store']");
expect(path.select(json).last.value, json['store']['bicycle']['price']);
expect(path.select(json).last.path, r"$['store']['bicycle']['price']");
});

test('Every price tag', () {
final path = JsonPath(r'$..price');
expect(path.toString(), r"$..['price']");
expect(path.select(json).length, 5);
// expect(path.select(json).first.value, json['store']);
// expect(path.select(json).first.path, r"$['store']");
// expect(path.select(json).last.value, json['store']['bicycle']['price']);
// expect(path.select(json).last.path, r"$['store']['bicycle']['price']");
});
});

group('Arrays', () {
test('Path with an index', () {
final path = JsonPath(r'$.store.book[0].title');
expect(path.toString(), r"$['store']['book'][0]['title']");
expect(path.select(json).single.value, 'Sayings of the Century');
expect(path.select(json).single.path, r"$['store']['book'][0]['title']");
});

test('All in array', () {
final path = JsonPath(r'$.store.book[*]');
expect(path.toString(), r"$['store']['book'][*]");
expect(path.select(json).length, 4);
expect(path.select(json).first.value, json['store']['book'][0]);
expect(path.select(json).first.path, r"$['store']['book'][0]");
expect(path.select(json).last.value, json['store']['book'][3]);
expect(path.select(json).last.path, r"$['store']['book'][3]");
});
});
}

0 comments on commit 3e0cff4

Please sign in to comment.