Skip to content

Commit 4924dde

Browse files
committed
dev.1
1 parent 5c0699c commit 4924dde

20 files changed

+167
-117
lines changed

CHANGELOG.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
## [Unreleased]
2+
## [0.0.0+dev.1] - 2020-07-27
23
### Added
34
- Tokenizer and AST
5+
- All-in-array selector
46

57
## 0.0.0+dev.0 - 2020-07-24
68
### Added
79
- Basic design draft
810

9-
[Unreleased]: https://github.com/f3ath/jessie/compare/0.0.0+dev.0...HEAD
11+
[Unreleased]: https://github.com/f3ath/jessie/compare/0.0.0+dev.1...HEAD
12+
[0.0.0+dev.1]: https://github.com/f3ath/jessie/compare/0.0.0+dev.0...0.0.0+dev.1

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
Jessie is a work-in-progress. Expect the API to change often. Feel free to join.
33

44
## Roadmap
5-
- [ ] Basic selectors: fields, indices
5+
- [x] Basic selectors: fields, indices
66
- [ ] Recursive descent (`..`)
7-
- [ ] Wildcard (`*`)
7+
- [x] Wildcard (`*`)
88
- [ ] Subscript (`[:2]`)
99
- [ ] Slice (`[1:10:2]`)
1010
- [ ] Union (`book[0, 1]`, `book[author, title, price]`)

lib/jessie.dart

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
library jessie;
33

44
export 'package:jessie/src/json_path.dart';
5+
export 'package:jessie/src/result.dart';

lib/src/ast.dart

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
class Node {
22
Node(this.value);
33

4+
/// Builds the AST from the list of tokens
45
static Node build(List<String> tokens) {
56
final root = Node(r'$');
67
if (tokens.isEmpty) {
@@ -24,7 +25,7 @@ class Node {
2425
children.add(stack.removeLast());
2526
}
2627
final brackets = stack.removeLast();
27-
brackets.children.addAll(children);
28+
brackets.children.addAll(children.reversed);
2829
stack.last.children.add(brackets);
2930
continue;
3031
}
@@ -35,4 +36,6 @@ class Node {
3536

3637
final String value;
3738
final children = <Node>[];
39+
40+
bool get isNumber => RegExp(r'^-?\d+$').hasMatch(value);
3841
}

lib/src/field.dart

-16
This file was deleted.

lib/src/filter.dart

-33
This file was deleted.

lib/src/index.dart

-16
This file was deleted.

lib/src/json_path.dart

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'package:jessie/src/ast.dart';
2-
import 'package:jessie/src/filter.dart';
3-
import 'package:jessie/src/match.dart';
4-
import 'package:jessie/src/root.dart';
2+
import 'package:jessie/src/selector/selector.dart';
3+
import 'package:jessie/src/selector/root.dart';
4+
import 'package:jessie/src/result.dart';
55
import 'package:jessie/src/state.dart';
66
import 'package:jessie/src/tokenize.dart';
77

@@ -14,14 +14,14 @@ class JsonPath {
1414
return JsonPath._(state.filter);
1515
}
1616

17-
JsonPath._(this._filter);
17+
JsonPath._(this._selector);
1818

19-
final Filter _filter;
19+
final Selector _selector;
2020

2121
/// Filters the given [json].
2222
/// Returns an Iterable of all elements found
23-
Iterable<PathMatch> filter(json) => _filter.call([PathMatch(json, '')]);
23+
Iterable<Result> select(json) => _selector([Result(json, '')]);
2424

2525
@override
26-
String toString() => _filter.toString();
26+
String toString() => _selector.toString();
2727
}

lib/src/match.dart

-7
This file was deleted.

lib/src/result.dart

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// A single matching result
2+
class Result<T> {
3+
Result(this.value, this.path);
4+
5+
/// The value
6+
final T value;
7+
8+
/// JSONPath to this result
9+
final String path;
10+
}

lib/src/root.dart

-13
This file was deleted.

lib/src/selector/all_in_array.dart

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import 'package:jessie/src/selector/selector.dart';
2+
import 'package:jessie/src/result.dart';
3+
4+
class AllInArray extends Selector {
5+
@override
6+
Iterable<Result> call(Iterable<Result> results) =>
7+
results.where((r) => r.value is List).map((r) {
8+
final val = r.value as List;
9+
final results = <Result>[];
10+
for (var i = 0; i < val.length; i++) {
11+
results.add(Result(val[i], r.path + '[$i]'));
12+
}
13+
return results;
14+
}).expand((_) => _);
15+
16+
@override
17+
String get expression => '[*]';
18+
}

lib/src/selector/field.dart

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import 'package:jessie/src/selector/selector.dart';
2+
import 'package:jessie/src/result.dart';
3+
4+
class Field extends Selector {
5+
Field(this.name);
6+
7+
final String name;
8+
9+
@override
10+
Iterable<Result> call(Iterable<Result> results) => results
11+
.where((r) => r.value is Map && r.value.containsKey(name))
12+
.map((r) => Result(r.value[name], r.path + toString()));
13+
14+
@override
15+
String get expression => "['$name']";
16+
}

lib/src/selector/index.dart

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import 'package:jessie/src/selector/selector.dart';
2+
import 'package:jessie/src/result.dart';
3+
4+
class Index extends Selector {
5+
Index(this.index);
6+
7+
final int index;
8+
9+
@override
10+
Iterable<Result> call(Iterable<Result> results) => results
11+
.where((r) => r.value is List && r.value.length > index + 1)
12+
.map((r) => Result(r.value[index], r.path + toString()));
13+
14+
@override
15+
String get expression => '[$index]';
16+
}

lib/src/selector/root.dart

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import 'package:jessie/src/selector/selector.dart';
2+
import 'package:jessie/src/result.dart';
3+
4+
class Root extends Selector {
5+
const Root();
6+
7+
@override
8+
Iterable<Result> call(Iterable<Result> results) =>
9+
results.map((m) => Result(m.value, toString()));
10+
11+
@override
12+
String get expression => r'$';
13+
}

lib/src/selector/selector.dart

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import 'package:jessie/src/result.dart';
2+
3+
/// Converts a set of results into a set of results
4+
abstract class Selector {
5+
const Selector();
6+
7+
/// Applies this filter to the [results]
8+
Iterable<Result> call(Iterable<Result> results);
9+
10+
/// The filter expression as string
11+
String get expression;
12+
13+
@override
14+
String toString() => expression;
15+
16+
/// Combines this expression with the [other]
17+
Selector then(Selector other) => _Chain(this, other);
18+
}
19+
20+
class _Chain extends Selector {
21+
_Chain(this.first, this.second);
22+
23+
final Selector first;
24+
25+
final Selector second;
26+
27+
@override
28+
Iterable<Result> call(Iterable<Result> results) => second(first(results));
29+
30+
@override
31+
String get expression => '$first$second';
32+
}

lib/src/state.dart

+18-7
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,48 @@
11
import 'package:jessie/src/ast.dart';
2-
import 'package:jessie/src/field.dart';
3-
import 'package:jessie/src/filter.dart';
4-
import 'package:jessie/src/index.dart';
2+
import 'package:jessie/src/selector/all_in_array.dart';
3+
import 'package:jessie/src/selector/field.dart';
4+
import 'package:jessie/src/selector/selector.dart';
5+
import 'package:jessie/src/selector/index.dart';
56

67
abstract class State {
78
State process(Node node);
89

9-
Filter get filter;
10+
Selector get filter;
1011
}
1112

1213
class Ready implements State {
1314
Ready(this.filter);
1415

1516
@override
16-
final Filter filter;
17+
final Selector filter;
1718

1819
@override
1920
State process(Node node) {
2021
if (node.value == '[') {
21-
return Ready(filter.then(Index(int.parse(node.children.first.value))));
22+
return Ready(filter.then(_brackets(node.children)));
2223
}
2324
if (node.value == '.') {
2425
return AwaitingField(filter);
2526
}
2627
throw StateError('Got ${node.value} in $this');
2728
}
29+
30+
Selector _brackets(List<Node> nodes) {
31+
if (nodes.length == 1) {
32+
final node = nodes.single;
33+
final val = node.value;
34+
if (val == '*') return AllInArray();
35+
if (node.isNumber) return Index(int.parse(nodes.first.value));
36+
}
37+
throw StateError('Unexpected bracket expression');
38+
}
2839
}
2940

3041
class AwaitingField implements State {
3142
AwaitingField(this.filter);
3243

3344
@override
34-
final Filter filter;
45+
final Selector filter;
3546

3647
@override
3748
State process(Node node) {

lib/src/tokenize.dart

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// Parses a JSONPath expression into a list of tokens
12
List<String> tokenize(String expr) {
23
final tokens = <String>[];
34
var pos = 0;

pubspec.yaml

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
name: jessie
2-
version: 0.0.0+dev.0
3-
homepage: https://github.com/f3ath/jessie
2+
version: 0.0.0+dev.1
43
description: JSONPath for Dart
5-
environment:
6-
sdk: ">=2.8.0 <3.0.0"
4+
homepage: "https://github.com/f3ath/jessie"
75

86
dev_dependencies:
9-
test: ^1.9.0
107
pedantic: ^1.9.0
8+
test: ^1.9.0
9+
10+
environment:
11+
sdk: ">=2.8.0 <3.0.0"

0 commit comments

Comments
 (0)