18 Commits

Author SHA1 Message Date
8a580e3b2f wasm-bindgen package.json에 keywords 생성하지 않는 문제 임시조치 2019-04-13 23:04:23 +09:00
d0e572ff56 README.md - fix link path 2019-04-13 22:47:11 +09:00
4a044ba250 jsonpath-wasm publish 2019-04-13 22:39:48 +09:00
35ef9f8c5e Remove firefix buid 2019-04-11 12:26:36 +09:00
753a822341 JsonPath evaluator - Google GA 추가 2019-04-10 18:19:04 +09:00
3276e7e18a 'jsonpath-rs' 버전 badge 적용 2019-04-10 18:04:38 +09:00
3b45f1c4a5 Unit test - 'wasm-bindgen-test' 적용 2019-04-10 17:26:07 +09:00
1c3656460e Javascript Selector 유닛테스트 완료 2019-04-10 17:01:07 +09:00
d263e30c91 NodeJs 0.1.7 - support Selector(0.1.9) 2019-04-09 16:13:09 +09:00
ceadbcec84 README.md - update 2019-04-09 13:31:31 +09:00
a15abe38fb JsonPath evaluator - add sample path list 2019-04-09 11:53:46 +09:00
7a106539d1 JsonPath evaluator - update 2019-04-08 23:19:33 +09:00
4ad783e40c webassembly - 'filter_ref_value' Value serialize 제거 2019-04-08 23:13:17 +09:00
0729a2a47f Bump up 0.1.9 2019-04-08 15:58:55 +09:00
30aa38379a Selector struct 추가 2019-04-08 15:21:10 +09:00
d955a1632c '..'토큰이 있을 때 필터 후 중복 생기는 문제 수정 2019-04-08 15:19:14 +09:00
8ec694090b JsonPath evaluator - update 2019-04-08 12:28:52 +09:00
d75b93612d 토큰 이후 배열이 왔을 때 필터링 되지 않는 문제 수정 2019-04-08 12:15:35 +09:00
66 changed files with 8490 additions and 932 deletions

View File

@ -3,7 +3,7 @@
<option name="channel" value="DEFAULT" />
<option name="command" value="test --package jsonpath_lib" />
<option name="allFeatures" value="false" />
<option name="nocapture" value="false" />
<option name="nocapture" value="true" />
<option name="backtrace" value="SHORT" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<envs />

12
.idea/runConfigurations/selector.xml generated Normal file
View File

@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="selector" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="channel" value="DEFAULT" />
<option name="command" value="test --package jsonpath_lib --test selector &quot;&quot;" />
<option name="allFeatures" value="false" />
<option name="nocapture" value="false" />
<option name="backtrace" value="SHORT" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<envs />
<method v="2" />
</configuration>
</component>

View File

@ -3,7 +3,7 @@
<option name="channel" value="DEFAULT" />
<option name="command" value="test --package jsonpath_lib --test serde &quot;&quot;" />
<option name="allFeatures" value="false" />
<option name="nocapture" value="true" />
<option name="nocapture" value="false" />
<option name="backtrace" value="SHORT" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<envs />

View File

@ -13,6 +13,8 @@ matrix:
- rust: stable
os: linux
env: RUST_BACKTRACE=1
addons:
chrome: stable
before_script:
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
@ -23,9 +25,12 @@ matrix:
- cargo test --verbose --all
- cd wasm
- wasm-pack build
- wasm-pack test --chrome --headless
- rust: stable
os: osx
env: RUST_BACKTRACE=1
addons:
chrome: stable
before_script:
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
@ -36,6 +41,7 @@ matrix:
- cargo test --verbose --all
- cd wasm
- wasm-pack build
- wasm-pack test --chrome --headless
- language: node_js
os: linux
node_js:

View File

@ -1,17 +1,19 @@
[package]
name = "jsonpath_lib"
version = "0.1.8"
version = "0.1.10"
authors = ["Changseok Han <freestrings@gmail.com>"]
description = "JsonPath in Rust and Webassembly - Webassembly Demo: https://freestrings.github.io/jsonpath"
description = "It is JsonPath engine written in Rust. it provide a similar API interface in Webassembly and Javascript also. - Webassembly Demo: https://freestrings.github.io/jsonpath"
readme = "README.md"
keywords = ["library", "jsonpath", "json", "webassembly"]
keywords = ["library", "jsonpath", "json", "webassembly", "nodejs", "javascript"]
repository = "https://github.com/freestrings/jsonpath"
documentation = "https://docs.rs/jsonpath_lib/0.1.0/jsonpath_lib"
license = "MIT"
categories = ["Parsing"]
[badges]
travis-ci = { repository = "freestrings/jsonpath", branch = "master" }

585
README.md
View File

@ -2,54 +2,283 @@
[![Build Status](https://travis-ci.org/freestrings/jsonpath.svg?branch=master)](https://travis-ci.org/freestrings/jsonpath)
![crates.io](https://img.shields.io/crates/v/jsonpath_lib.svg)
![Crates.io](https://img.shields.io/crates/d/jsonpath_lib.svg?label=%60jsonpath_lib%60%20crates.io%20downloads)
![npm](https://img.shields.io/npm/dt/jsonpath-rs.svg?label=%60jsonpath-rs%60%20npm%20downloads)
![Crates.io](https://img.shields.io/crates/d/jsonpath_lib.svg?label=%60jsonpath_lib%60%20downloads)
![npm](https://img.shields.io/npm/v/jsonpath-rs.svg?label=npm%20%60jsonpath-rs%60)
![npm](https://img.shields.io/npm/dt/jsonpath-rs.svg?label=%60jsonpath-rs%60%20downloads)
![npm](https://img.shields.io/npm/v/jsonpath-wasm.svg?label=npm%20%60jsonpath-wasm%60)
`Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. `Webassembly``Javascript`에서도 역시 동일한 API 인터페이스를 제공 한다.
`Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. `Webassembly``Javascript`에서도 유사한 API 인터페이스를 제공 한다.
It is an implementation for [JsonPath](https://goessner.net/articles/JsonPath/) written in `Rust`. it provide the same API interface in `Webassembly` and` Javascript` also.
It is JsonPath [JsonPath](https://goessner.net/articles/JsonPath/) engine written in `Rust`. it provide a similar API interface in `Webassembly` and` Javascript` also.
- [Webassembly Demo](https://freestrings.github.io/jsonpath/)
- [Rust documentation](https://docs.rs/jsonpath_lib/0.1.6/jsonpath_lib)
- [NPM jsonpath-wasm - webassembly](https://www.npmjs.com/package/jsonpath-wasm)
- [NPM jsonpath-rs - native addon](https://www.npmjs.com/package/jsonpath-rs)
## Why?
## Rust API
To enjoy Rust!
- [jsonpath_lib crate](#jsonpath_lib-crate)
- [Rust - jsonpath::Selector struct](#rust---jsonpathselector-struct)
- [Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)](#rust---jsonpathselectjson-serde_jsonvaluevalue-jsonpath-str)
- [Rust - jsonpath::select_as_str(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_as_strjson-str-jsonpath-str)
- [Rust - jsonpath::select_as\<T: `serde::de::DeserializeOwned`\>(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_ast-serdededeserializeownedjson-str-jsonpath-str)
- [Rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str)
- [Rust - jsonpath::selector(json: &serde_json::value::Value)](#rust---jsonpathselectorjson-serde_jsonvaluevalue)
- [Rust - jsonpath::selector_as\<T: `serde::de::DeserializeOwned`\>(json: &serde_json::value::Value)](#rust---jsonpathselector_ast-serdededeserializeownedjson-serde_jsonvaluevalue)
- [Rust - Other Examples](https://github.com/freestrings/jsonpath/wiki/rust-examples)
## API
## Javascript API
[With Javascript](#with-javascript)
- [npm package](#npm-package)
- [Javascript - jsonpath.Selector class](#javascript---selector-class)
- [Javascript - jsonpath.select(json: string|object, jsonpath: string)](#javascript---jsonpathselectjson-stringobject-jsonpath-string)
- [Javascript - jsonpath.compile(jsonpath: string)](#javascript---jsonpathcompilejsonpath-string)
- [Javascript - jsonpath.selector(json: string|object)](#javascript---jsonpathselectorjson-stringobject)
- [Javascript - allocJson, deallocJson (Webassembly Only)](#javascript---allocjson-deallocjson-webassembly-only)
- [Javascript - Other Examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples)
- [jsonpath-wasm library](#jsonpath-wasm-library)
- [jsonpath-rs library](#jsonpath-rs-library-only-nodejs)
- [javascript - jsonpath.select(json: string|object, jsonpath: string)](#javascript---jsonpathselectjson-stringobject-jsonpath-string)
- [javascript - jsonpath.compile(jsonpath: string)](#javascript---jsonpathcompilejsonpath-string)
- [javascript - jsonpath.selector(json: string|object)](#javascript---jsonpathselectorjson-stringobject)
- [javascript - alloc_json, dealloc_json](#javascript---alloc_json-dealloc_json)
- [javascript-wasm - examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples)
---
[With Rust (as library)](#with-rust-as-library)
### Rust API
- [jsonpath_lib library](#jsonpath_lib-library)
- [rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)](#rust---jsonpathselectjson-serde_jsonvaluevalue-jsonpath-str)
- [rust - jsonpath::select_as_str(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_as_strjson-str-jsonpath-str)
- [rust - jsonpath::select_as\<T: `serde::de::DeserializeOwned`\>(json_str: &str, jsonpath: &str)](#rust---jsonpathselect_ast-serdededeserializeownedjson-str-jsonpath-str)
- [rust - jsonpath::compile(jsonpath: &str)](#rust---jsonpathcompilejsonpath-str)
- [rust - jsonpath::selector(json: &serde_json::value::Value)](#rust---jsonpathselectorjson-serde_jsonvaluevalue)
- [rust - jsonpath::selector_as\<T: `serde::de::DeserializeOwned`\>(json: &serde_json::value::Value)](#rust---jsonpathselector_ast-serdededeserializeownedjson-serde_jsonvaluevalue)
- [rust - examples](https://github.com/freestrings/jsonpath/wiki/rust-examples)
#### jsonpath_lib crate
[Go to creates.io](https://crates.io/crates/jsonpath_lib)
[With AWS API Gateway](#)
```rust
extern crate jsonpath_lib as jsonpath;
#[macro_use]
extern crate serde_json;
```
[Simple time check - webassembly](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck---jsonpath-wasm)
#### Rust - jsonpath::Selector struct
[Simple time check - native addon for NodeJs](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck-jsonpath-native)
```rust
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Friend {
name: String,
age: Option<u8>,
}
## With Javascript
let json_obj = json!({
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]});
### jsonpath-wasm library
let mut selector = Selector::new();
let result = selector
.path("$..[?(@.age >= 30)]").unwrap()
// .value_from_str(&serde_json::to_string(&json_obj).unwrap() /*&str*/).unwrap()
// .value_from(&json_obj /*&impl serde::ser::Serialize*/).unwrap()
.value((&json_obj /*serde_json::value::Value*/ ).into()).unwrap()
.select_to_value().unwrap();
assert_eq!(json!([{"name": "친구3", "age": 30}]), result);
let result = selector.select_to_str().unwrap();
assert_eq!(r#"[{"name":"친구3","age":30}]"#, result);
let result = selector.select_to::<Vec<Friend>>().unwrap();
assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result);
```
#### Rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)
```rust
let json_obj = json!({
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]});
let json = jsonpath::select(&json_obj, "$..friends[0]").unwrap();
let ret = json!([
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
]);
assert_eq!(json, ret);
```
#### Rust - jsonpath::select_as_str(json: &str, jsonpath: &str)
```rust
let ret = jsonpath::select_as_str(r#"
{
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
}
"#, "$..friends[0]").unwrap();
assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#);
```
#### Rust - jsonpath::select_as\<T: `serde::de::DeserializeOwned`\>(json: &str, jsonpath: &str)
```rust
#[derive(Deserialize, PartialEq, Debug)]
struct Person {
name: String,
age: u8,
phones: Vec<String>,
}
let ret: Person = jsonpath::select_as(r#"
{
"person":
{
"name": "Doe John",
"age": 44,
"phones": [
"+44 1234567",
"+44 2345678"
]
}
}
"#, "$.person").unwrap();
let person = Person {
name: "Doe John".to_string(),
age: 44,
phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()],
};
assert_eq!(person, ret);
```
#### Rust - jsonpath::compile(jsonpath: &str)
```rust
let mut template = jsonpath::compile("$..friends[0]");
let json_obj = json!({
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]});
let json = template(&json_obj).unwrap();
let ret = json!([
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
]);
assert_eq!(json, ret);
```
#### Rust - jsonpath::selector(json: &serde_json::value::Value)
```rust
let json_obj = json!({
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]});
let mut selector = jsonpath::selector(&json_obj);
let json = selector("$..friends[0]").unwrap();
let ret = json!([
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
]);
assert_eq!(json, ret);
let json = selector("$..friends[1]").unwrap();
let ret = json!([
{"name": "친구4"},
{"name": "친구2", "age": 20}
]);
assert_eq!(json, ret);
```
#### Rust - jsonpath::selector_as\<T: `serde::de::DeserializeOwned`\>(json: &serde_json::value::Value)
```rust
let json_obj = json!({
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]});
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Friend {
name: String,
age: Option<u8>,
}
let mut selector = jsonpath::selector_as::<Vec<Friend>>(&json_obj);
let json = selector("$..friends[0]").unwrap();
let ret = vec!(
Friend { name: "친구3".to_string(), age: Some(30) },
Friend { name: "친구1".to_string(), age: Some(20) }
);
assert_eq!(json, ret);
let json = selector("$..friends[1]").unwrap();
let ret = vec!(
Friend { name: "친구4".to_string(), age: None },
Friend { name: "친구2".to_string(), age: Some(20) }
);
assert_eq!(json, ret);
```
---
### Javascript API
#### npm package
##### jsonpath-wasm
*(not yet published `jsonpath-wasm`)*
```javascript
// browser
import * as jsonpath from "jsonpath-wasm";
@ -57,15 +286,92 @@ import * as jsonpath from "jsonpath-wasm";
const jsonpath = require('jsonpath-wasm');
```
### jsonpath-rs library (Only NodeJS)
##### jsonpath-rs (NodeJS only)
`jsonpath-rs` is native addon for NodeJs
[Goto npmjs.org](https://www.npmjs.com/package/jsonpath-rs)
```javascript
const jsonpath = require('jsonpath-rs');
```
### javascript - jsonpath.select(json: string|object, jsonpath: string)
#### javascript - Selector class
##### jsonpath-wasm
`wasm-bindgen` 리턴 타입 제약 때문에 빌더 패턴은 지원하지 않는다.
It does not support `builder-pattern` due to the `return type` restriction of `wasm-bindgen`.
```javascript
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let ret = [
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
];
let selector = new jsonpath.Selector();
selector.path('$..friends[0]');
selector.value(jsonObj);
let selectToObj = selector.selectTo();
let selectToString = selector.selectToStr();
console.log(
JSON.stringify(ret) == JSON.stringify(selectToObj),
JSON.stringify(ret) == selectToString
);
// => true, true
```
##### jsonpath-rs
```javascript
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let ret = [
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
];
let selector = new jsonpath.Selector()
.path('$..friends[0]')
.value(jsonObj);
let selectToObj = selector.selectTo();
let selectToString = selector.selectToStr();
console.log(
JSON.stringify(ret) == JSON.stringify(selectToObj),
JSON.stringify(ret) == selectToString
);
// => true, true
```
#### Javascript - jsonpath.select(json: string|object, jsonpath: string)
```javascript
let jsonObj = {
@ -98,7 +404,7 @@ console.log(
// => true, true
```
### javascript - jsonpath.compile(jsonpath: string)
#### Javascript - jsonpath.compile(jsonpath: string)
```javascript
let template = jsonpath.compile('$..friends[0]');
@ -157,7 +463,7 @@ console.log(
// => true, true
```
### javascript - jsonpath.selector(json: string|object)
#### Javascript - jsonpath.selector(json: string|object)
```javascript
let jsonObj = {
@ -198,16 +504,13 @@ console.log(
// => true, true
```
### javascript - alloc_json, dealloc_json
#### Javascript - allocJson, deallocJson (Webassembly Only)
wasm-bindgen은 Javascript와 Webassembly간 값을 주고받을 때 JSON 객체는 String으로 변환되기 때문에, 반복해서 사용되는 JSON 객체는 Webassembly 영역에 생성해 두면 성능에 도움이 된다.
*(not supported in `jsonpath-rs`)*
wasm-bindgen은 Javascript와 Webassembly 간 값을 주고받을 때 JSON 객체는 String으로 변환되기 때문에, 반복해서 사용되는 JSON 객체를 Webassembly 영역에 생성해 두면 성능에 도움이 된다.
Since wasm-bindgen converts JSON objects to String when exchanging values between Javascript and Webassembly, it is helpful to create repeated Json objects in Webassembly area.
Since wasm-bindgen converts JSON objects to String when exchanging values between Javascript and Webassembly, creating frequently used JSON objects in the WebAssembly area helps performance.
```javascript
const jsonpath = require('@nodejs/jsonpath-wasm');
const jsonpath = require('jsonpath-wasm');
let jsonObj = {
"school": {
@ -223,7 +526,7 @@ let jsonObj = {
};
// allocate jsonObj in webassembly
let ptr = jsonpath.alloc_json(jsonObj);
let ptr = jsonpath.allocJson(jsonObj);
// `0` is invalid pointer
if(ptr == 0) {
@ -254,197 +557,5 @@ console.log(
// => true true true true true
jsonpath.dealloc_json(ptr);
jsonpath.deallocJson(ptr);
```
## With Rust (as library)
### jsonpath_lib library
```rust
extern crate jsonpath_lib as jsonpath;
#[macro_use]
extern crate serde_json;
```
### rust - jsonpath::select(json: &serde_json::value::Value, jsonpath: &str)
```rust
let json_obj = json!({
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]});
let json = jsonpath::select(&json_obj, "$..friends[0]").unwrap();
let ret = json!([
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
]);
assert_eq!(json, ret);
```
### rust - jsonpath::select_as_str(json: &str, jsonpath: &str)
```rust
let ret = jsonpath::select_as_str(r#"
{
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
}
"#, "$..friends[0]").unwrap();
assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#);
```
### rust - jsonpath::select_as\<T: `serde::de::DeserializeOwned`\>(json: &str, jsonpath: &str)
```rust
#[derive(Deserialize, PartialEq, Debug)]
struct Person {
name: String,
age: u8,
phones: Vec<String>,
}
let ret: Person = jsonpath::select_as(r#"
{
"person":
{
"name": "Doe John",
"age": 44,
"phones": [
"+44 1234567",
"+44 2345678"
]
}
}
"#, "$.person").unwrap();
let person = Person {
name: "Doe John".to_string(),
age: 44,
phones: vec!["+44 1234567".to_string(), "+44 2345678".to_string()],
};
assert_eq!(person, ret);
```
### rust - jsonpath::compile(jsonpath: &str)
```rust
let mut template = jsonpath::compile("$..friends[0]");
let json_obj = json!({
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]});
let json = template(&json_obj).unwrap();
let ret = json!([
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
]);
assert_eq!(json, ret);
```
### rust - jsonpath::selector(json: &serde_json::value::Value)
```rust
let json_obj = json!({
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]});
let mut selector = jsonpath::selector(&json_obj);
let json = selector("$..friends[0]").unwrap();
let ret = json!([
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
]);
assert_eq!(json, ret);
let json = selector("$..friends[1]").unwrap();
let ret = json!([
{"name": "친구4"},
{"name": "친구2", "age": 20}
]);
assert_eq!(json, ret);
```
### rust - jsonpath::selector_as\<T: `serde::de::DeserializeOwned`\>(json: &serde_json::value::Value)
```rust
let json_obj = json!({
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]});
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Friend {
name: String,
age: Option<u8>,
}
let mut selector = jsonpath::selector_as::<Vec<Friend>>(&json_obj);
let json = selector("$..friends[0]").unwrap();
let ret = vec!(
Friend { name: "친구3".to_string(), age: Some(30) },
Friend { name: "친구1".to_string(), age: Some(20) }
);
assert_eq!(json, ret);
let json = selector("$..friends[1]").unwrap();
let ret = vec!(
Friend { name: "친구4".to_string(), age: None },
Friend { name: "친구2".to_string(), age: Some(20) }
);
assert_eq!(json, ret);
```

View File

@ -3,6 +3,7 @@ extern crate jsonpath_lib as jsonpath;
extern crate serde;
extern crate serde_json;
extern crate test;
extern crate bencher;
use std::io::Read;
@ -10,6 +11,8 @@ use serde::Deserialize;
use serde_json::Value;
use self::test::Bencher;
use jsonpath::ref_value::model::RefValue;
use serde::ser::Serialize;
fn read_json(path: &str) -> String {
let mut f = std::fs::File::open(path).unwrap();
@ -101,4 +104,25 @@ fn bench_select_as(b: &mut Bencher) {
let _: Book = jsonpath::select_as(&json, r#"$..book[?(@.price<30 && @.category=="fiction")][0]"#).unwrap();
}
});
}
#[bench]
fn bench_serde_ser(b: &mut Bencher) {
let json = get_json();
b.iter(move || {
for _ in 1..100 {
let _: RefValue = json.serialize(jsonpath::ref_value::ser::Serializer).unwrap().into();
}
});
}
#[bench]
fn bench_serde_de(b: &mut Bencher) {
let json_string = get_string();
let json_str = json_string.as_str();
b.iter(move || for _ in 1..100 {
let _: RefValue = serde_json::from_str(json_str).unwrap();
});
}

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/examples" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/benches" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CargoProjects">
<cargoProject FILE="$PROJECT_DIR$/Cargo.toml" />
</component>
<component name="RustProjectSettings">
<option name="toolchainHomeDirectory" value="$USER_HOME$/.cargo/bin" />
</component>
</project>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/bench_bin.iml" filepath="$PROJECT_DIR$/.idea/bench_bin.iml" />
</modules>
</component>
</project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>

View File

@ -1,152 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="3fa6f740-0ee1-4afb-b0ae-9239bf5ced3d" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/../bench.rs" beforeDir="false" afterPath="$PROJECT_DIR$/../bench.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/main.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../bench_node_vs_rust.sh" beforeDir="false" afterPath="$PROJECT_DIR$/../bench_node_vs_rust.sh" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../javascript/bench.js" beforeDir="false" afterPath="$PROJECT_DIR$/../javascript/bench.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../../nodejs/lib/index.js" beforeDir="false" afterPath="$PROJECT_DIR$/../../nodejs/lib/index.js" afterDir="false" />
<change beforePath="$PROJECT_DIR$/../../nodejs/native/src/lib.rs" beforeDir="false" afterPath="$PROJECT_DIR$/../../nodejs/native/src/lib.rs" afterDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/../.." />
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/../../src/lib.rs" />
<option value="$PROJECT_DIR$/src/main.rs" />
</list>
</option>
</component>
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="67" />
<option name="y" value="27" />
<option name="width" value="1533" />
<option name="height" value="1053" />
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectView">
<navigator proportions="" version="1">
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="Scope" />
<pane id="PackagesPane" />
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="bench_bin" type="b2602c69:ProjectViewProjectNode" />
<item name="bench_bin" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="bench_bin" type="b2602c69:ProjectViewProjectNode" />
<item name="bench_bin" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
</panes>
</component>
<component name="PropertiesComponent">
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="org.rust.cargo.project.model.PROJECT_DISCOVERY" value="true" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="3fa6f740-0ee1-4afb-b0ae-9239bf5ced3d" name="Default Changelist" comment="" />
<created>1552690262696</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1552690262696</updated>
</task>
<servers />
</component>
<component name="ToolWindowManager">
<frame x="67" y="25" width="1853" height="1055" extended-state="6" />
<layout>
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.23076923" />
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
<window_info id="Designer" order="2" />
<window_info id="Favorites" order="3" side_tool="true" />
<window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" />
<window_info anchor="bottom" id="Run" order="2" weight="0.32829374" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
<window_info anchor="bottom" id="TODO" order="6" />
<window_info anchor="bottom" id="Version Control" order="7" />
<window_info anchor="bottom" id="Terminal" order="8" />
<window_info anchor="bottom" id="Event Log" order="9" side_tool="true" />
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
<window_info anchor="right" id="Maven" order="3" />
<window_info anchor="right" id="Cargo" order="4" />
<window_info anchor="right" id="Palette&#9;" order="5" />
</layout>
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/../../src/lib.rs">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="353">
<caret line="297" column="1" lean-forward="true" selection-start-line="297" selection-start-column="1" selection-end-line="297" selection-end-column="1" />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.39/src/de.rs">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="279">
<caret line="2311" column="47" selection-start-line="2311" selection-start-column="47" selection-end-line="2311" selection-end-column="47" />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/str/mod.rs">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="197">
<caret line="3895" column="11" selection-start-line="3895" selection-start-column="11" selection-end-line="3895" selection-end-column="11" />
<folding>
<element signature="e#126082#126083#0" expanded="true" />
<element signature="e#126120#126121#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/main.rs">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-680">
<caret line="6" column="13" selection-start-line="6" selection-start-column="13" selection-end-line="6" selection-end-column="13" />
</state>
</provider>
</entry>
</component>
</project>

View File

@ -37,6 +37,8 @@ __extra () {
printf "\n"
sleep 1
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm - compile-alloc: " && time ./bench.sh wasmCompileAlloc ${ITER}
sleep 1
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-wasm - Selector: " && time ./bench.sh wasmSelectorClass ${ITER}
}
if [ "$1" = "extra" ]; then

View File

@ -42,7 +42,7 @@ function getJson() {
}
const path = '$..book[?(@.price<30 && @.category=="fiction")]';
const jp = require('jsonpath');
const jpw = require('@nodejs/jsonpath-wasm');
const jpw = require('jsonpath-wasm');
const jpwRs = require('jsonpath-rs');
function jsonpath() {
@ -86,7 +86,7 @@ function wasmCompile() {
}
function wasmCompileAlloc() {
let ptr = jpw.alloc_json(getJson());
let ptr = jpw.allocJson(getJson());
if (ptr == 0) {
console.error('Invalid pointer');
return;
@ -98,7 +98,7 @@ function wasmCompileAlloc() {
let _ = template(ptr);
}
} finally {
jpw.dealloc_json(ptr);
jpw.deallocJson(ptr);
}
}
@ -109,7 +109,7 @@ function wasmSelect() {
}
function wasmSelectAlloc() {
let ptr = jpw.alloc_json(getJson());
let ptr = jpw.allocJson(getJson());
if (ptr == 0) {
console.error('Invalid pointer');
return;
@ -120,7 +120,16 @@ function wasmSelectAlloc() {
let _ = jpw.select(ptr, path);
}
} finally {
jpw.dealloc_json(ptr);
jpw.deallocJson(ptr);
}
}
function wasmSelectorClass() {
let selector = new jpw.Selector();
for (var i = 0; i < iter; i++) {
selector.path(path);
selector.value(jsonStr);
let _ = selector.selectToStr();
}
}

View File

@ -9,6 +9,7 @@ WASM_WWW="${WASM}"/www
WASM_WWW_BENCH="${WASM}"/www_bench
WASM_BROWSER_PKG="${WASM}"/browser_pkg
WASM_NODEJS_PKG="${WASM}"/nodejs_pkg
WASM_ALL_PKG="${WASM}"/all_pkg
BENCHES="${DIR}"/benches
BENCHES_JS="${BENCHES}"/javascript
NODEJS="${DIR}"/nodejs
@ -31,6 +32,7 @@ __msg "clean"
rm -rf \
"${WASM_NODEJS_PKG}" \
"${WASM_BROWSER_PKG}" \
"${WASM_ALL_PKG}" \
"${BENCHES_JS}"/node_modules \
"${NODEJS}"/node_modules \
"${WASM_WWW}"/node_modules \
@ -50,27 +52,44 @@ cd "${WASM_WWW_BENCH}" && npm install
cd "${NODEJS}" && npm install
cd "${BENCHES_JS}" && npm install
echo
echo
__msg "nodejs"
cd "${NODEJS}" && npm test
echo
echo
__msg "wasm-pack"
cd "${WASM}" && \
wasm-pack build --target=nodejs --scope nodejs --out-dir nodejs_pkg && \
cd "${WASM_NODEJS_PKG}" && npm link
wasm-pack build --release --target=nodejs --out-dir "${WASM_NODEJS_PKG}"
cd "${WASM}" && \
wasm-pack build --target=browser --scope browser --out-dir browser_pkg && \
cd "${WASM_BROWSER_PKG}" && npm link
wasm-pack build --release --target=browser --out-dir "${WASM_BROWSER_PKG}" && \
wasm-pack test --chrome --firefox --headless
__msg "wasm npm packaging"
cp -r "${WASM_BROWSER_PKG}" "${WASM_ALL_PKG}/" && \
sed "s/require[\(]'\.\/jsonpath_wasm_bg/require\('\.\/jsonpath_wasm_nodejs/" "${WASM_NODEJS_PKG}/jsonpath_wasm.js" \
> "${WASM_ALL_PKG}/jsonpath_wasm_main.js" && \
sed "s/require[\(]'\.\/jsonpath_wasm/require\('\.\/jsonpath_wasm_main/" "${WASM_NODEJS_PKG}/jsonpath_wasm_bg.js" \
> "${WASM_ALL_PKG}/jsonpath_wasm_nodejs.js" && \
jq ".files += [\"jsonpath_wasm_nodejs.js\"]" ${WASM_ALL_PKG}/package.json \
| jq ".main = \"jsonpath_wasm_main.js\"" \
| jq ".keywords += [\"jsonpath\", \"json\", \"webassembly\", \"parsing\", \"rust\"]" \
> ${WASM_ALL_PKG}/temp.json && \
mv -v "${WASM_ALL_PKG}/temp.json" "${WASM_ALL_PKG}/package.json" && \
cd "${WASM_ALL_PKG}" && npm link
echo
__msg "link"
cd "${WASM_WWW}" && \
npm link @browser/jsonpath-wasm
npm link jsonpath-wasm
cd "${WASM_WWW_BENCH}" && \
npm link @browser/jsonpath-wasm
npm link jsonpath-wasm
cd "${BENCHES_JS}" && \
npm link @nodejs/jsonpath-wasm && \
npm link jsonpath-wasm && \
npm link jsonpath-rs
echo

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -52,47 +52,50 @@
/******/ function promiseResolve() { return Promise.resolve(); }
/******/
/******/ var wasmImportObjects = {
/******/ "../browser_pkg/jsonpath_wasm_bg.wasm": function() {
/******/ "../all_pkg/jsonpath_wasm_bg.wasm": function() {
/******/ return {
/******/ "./jsonpath_wasm": {
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ },
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ },
/******/ "__wbindgen_cb_forget": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
/******/ },
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
/******/ },
/******/ "__widl_f_log_1_": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__widl_f_log_1_"](p0i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__widl_f_log_1_"](p0i32);
/******/ },
/******/ "__wbindgen_number_get": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_number_get"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_number_get"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_is_string": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
/******/ },
/******/ "__wbindgen_string_get": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
/******/ },
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_closure_wrapper102": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper102"](p0i32,p1i32,p2i32);
/******/ "__wbindgen_rethrow": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_rethrow"](p0i32);
/******/ },
/******/ "__wbindgen_closure_wrapper104": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper104"](p0i32,p1i32,p2i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper104"](p0i32,p1i32,p2i32);
/******/ },
/******/ "__wbindgen_closure_wrapper106": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper106"](p0i32,p1i32,p2i32);
/******/ }
/******/ }
/******/ };
@ -182,7 +185,7 @@
/******/
/******/ // Fetch + compile chunk loading for webassembly
/******/
/******/ var wasmModules = {"0":["../browser_pkg/jsonpath_wasm_bg.wasm"]}[chunkId] || [];
/******/ var wasmModules = {"0":["../all_pkg/jsonpath_wasm_bg.wasm"]}[chunkId] || [];
/******/
/******/ wasmModules.forEach(function(wasmModuleId) {
/******/ var installedWasmModuleData = installedWasmModules[wasmModuleId];
@ -192,7 +195,7 @@
/******/ promises.push(installedWasmModuleData);
/******/ else {
/******/ var importObject = wasmImportObjects[wasmModuleId]();
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"c615fa3fad4c084c8bcd"}[wasmModuleId] + ".module.wasm");
/******/ var req = fetch(__webpack_require__.p + "" + {"../all_pkg/jsonpath_wasm_bg.wasm":"ddd003b015308ef8b732"}[wasmModuleId] + ".module.wasm");
/******/ var promise;
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {

Binary file not shown.

41
docs/bootstrap.js vendored
View File

@ -52,47 +52,50 @@
/******/ function promiseResolve() { return Promise.resolve(); }
/******/
/******/ var wasmImportObjects = {
/******/ "../browser_pkg/jsonpath_wasm_bg.wasm": function() {
/******/ "../all_pkg/jsonpath_wasm_bg.wasm": function() {
/******/ return {
/******/ "./jsonpath_wasm": {
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ },
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ },
/******/ "__wbindgen_cb_forget": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
/******/ },
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
/******/ },
/******/ "__widl_f_log_1_": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__widl_f_log_1_"](p0i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__widl_f_log_1_"](p0i32);
/******/ },
/******/ "__wbindgen_number_get": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_number_get"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_number_get"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_is_string": function(p0i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_is_string"](p0i32);
/******/ },
/******/ "__wbindgen_string_get": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_get"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_object_clone_ref": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_clone_ref"](p0i32);
/******/ },
/******/ "__wbindgen_throw": function(p0i32,p1i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_throw"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_closure_wrapper102": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper102"](p0i32,p1i32,p2i32);
/******/ "__wbindgen_rethrow": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_rethrow"](p0i32);
/******/ },
/******/ "__wbindgen_closure_wrapper104": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../browser_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper104"](p0i32,p1i32,p2i32);
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper104"](p0i32,p1i32,p2i32);
/******/ },
/******/ "__wbindgen_closure_wrapper106": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper106"](p0i32,p1i32,p2i32);
/******/ }
/******/ }
/******/ };
@ -182,7 +185,7 @@
/******/
/******/ // Fetch + compile chunk loading for webassembly
/******/
/******/ var wasmModules = {"0":["../browser_pkg/jsonpath_wasm_bg.wasm"]}[chunkId] || [];
/******/ var wasmModules = {"0":["../all_pkg/jsonpath_wasm_bg.wasm"]}[chunkId] || [];
/******/
/******/ wasmModules.forEach(function(wasmModuleId) {
/******/ var installedWasmModuleData = installedWasmModules[wasmModuleId];
@ -192,7 +195,7 @@
/******/ promises.push(installedWasmModuleData);
/******/ else {
/******/ var importObject = wasmImportObjects[wasmModuleId]();
/******/ var req = fetch(__webpack_require__.p + "" + {"../browser_pkg/jsonpath_wasm_bg.wasm":"c615fa3fad4c084c8bcd"}[wasmModuleId] + ".module.wasm");
/******/ var req = fetch(__webpack_require__.p + "" + {"../all_pkg/jsonpath_wasm_bg.wasm":"ddd003b015308ef8b732"}[wasmModuleId] + ".module.wasm");
/******/ var promise;
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {

Binary file not shown.

View File

@ -1,9 +1,82 @@
<!DOCTYPE html>
<html>
<head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-3020058-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-3020058-1');
</script>
<meta charset="utf-8">
<meta property="og:image" content="https://avatars0.githubusercontent.com/u/1104423?s=400&amp;v=4"/>
<meta property="og:site_name" content="GitHub"/>
<meta property="og:type" content="object"/>
<meta property="og:title" content="freestrings/jsonpath"/>
<meta property="og:url" content="https://github.com/freestrings/jsonpath"/>
<meta property="og:description" content="JsonPath evaluator with Webassembly via Rust - freestrings/jsonpath"/>
<title>JsonPath evaluator - Webassembly via Rust</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
/**
* GitHub Corners, page css
* Author: Tim Holman
*/
.code textarea {
border: 2px solid #eee;
outline: 0px;
height: 100%;
width: 100%;
font-family: monospace;
font-size: 10px;
}
.github-corner:hover .octo-arm {
animation: octocat-wave 560ms ease-in-out;
}
@keyframes octocat-wave {
0% {
transform: rotate(0deg);
}
20% {
transform: rotate(-25deg);
}
40% {
transform: rotate(10deg);
}
60% {
transform: rotate(-25deg);
}
80% {
transform: rotate(10deg);
}
100% {
transform: rotate(0deg);
}
}
@media (max-width: 500px) {
.github-corner:hover .octo-arm {
animation: none;
}
.github-corner .octo-arm {
animation: octocat-wave 560ms ease-in-out;
}
}
</style>
</head>
<body role="document">
<div class="container">
@ -15,7 +88,59 @@
</div>
-->
<div class="row">
<div class="col-md-6">
<div class="col-md-3">
<span class="badge badge-dark" style="margin-bottom: 15px">JsonPath</span> <span>(click to try)</span>
<table class="table">
<tbody>
<tr>
<td class="path"><a href="#/$.store.book[*].author">$.store.book[*].author</a></td>
</tr>
<tr>
<td class="path"><a href="#$..author">$..author</a></td>
</tr>
<tr>
<td class="path"><a href="#">$.store.*</a></td>
</tr>
<tr>
<td class="path"><a href="#">$.store..price</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[2]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[-2]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[0,1]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[:2]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[1:2]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[-2:]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[2:]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[?(@.isbn)]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$.store.book[?(@.price < 10)]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..*</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]</a></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-4">
<span class="badge badge-dark" style="margin-bottom: 15px">Evaluator</span>
<div class="form-group">
<textarea id="json-example" class="form-control" style="min-width: 100%" rows="20"></textarea>
@ -29,12 +154,21 @@
</div>
</div>
</div>
<div class="col-md-6">
<div class="col-md-4">
<span class="badge badge-dark" style="margin-bottom: 15px">Result</span>
<pre class="prettyprint result" id="read-result" style="background-color: transparent; border: none;"></pre>
</div>
</div>
</div>
<a href="https://github.com/freestrings/jsonpath" class="github-corner" aria-label="View source on GitHub">
<svg width="80" height="80" viewBox="0 0 250 250" style="position: absolute; top: 0px; right: 0px; border: 0px;" aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" fill="#151513"></path>
<path class="octo-arm" d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="#ffffff" style="transform-origin: 130px 106px;"></path>
<path class="octo-body"
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
fill="#ffffff"></path>
</svg>
</a>
<script src="./bootstrap.js"></script>
</body>
</html>

2
examples/browser/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
dist

5
examples/browser/bootstrap.js vendored Normal file
View File

@ -0,0 +1,5 @@
// A dependency graph that contains any wasm must all be imported
// asynchronously. This `bootstrap.js` file does the single async import, so
// that no one else needs to worry about it again.
import("./index.js")
.catch(e => console.error("Error importing `index.js`:", e));

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jsonpath-wasm-browser-example</title>
</head>
<body>
<script src="./bootstrap.js"></script>
</body>
</html>

32
examples/browser/index.js Normal file
View File

@ -0,0 +1,32 @@
import * as jsonpath from "jsonpath-wasm";
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let ret = [
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
];
let selector = new jsonpath.Selector();
selector.path('$..friends[0]');
selector.value(jsonObj);
let selectToObj = selector.selectTo();
let selectToString = selector.selectToStr();
console.log(
JSON.stringify(ret) == JSON.stringify(selectToObj),
JSON.stringify(ret) == selectToString
);

5324
examples/browser/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
{
"name": "jsonpath-wasm-browser-example",
"version": "0.1.0",
"main": "index.js",
"scripts": {
"build": "webpack --config webpack.config.js",
"start": "webpack-dev-server"
},
"devDependencies": {
"copy-webpack-plugin": "^5.0.1",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
}
}

View File

@ -0,0 +1,14 @@
const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require('path');
module.exports = {
entry: "./bootstrap.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bootstrap.js",
},
mode: "development",
plugins: [
new CopyWebpackPlugin(['index.html'])
]
};

2
examples/nodejs-rs/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
dist

View File

@ -0,0 +1,31 @@
const jsonpath = require('jsonpath-rs');
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let ret = [
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
];
let selector = new jsonpath.Selector();
selector.path('$..friends[0]');
selector.value(jsonObj);
let selectToObj = selector.selectTo();
let selectToString = selector.selectToStr();
console.log(
JSON.stringify(ret) == JSON.stringify(selectToObj),
JSON.stringify(ret) == selectToString
);

658
examples/nodejs-rs/package-lock.json generated Normal file
View File

@ -0,0 +1,658 @@
{
"name": "jsonpath-rs-example",
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"ansi-escape-sequences": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-4.1.0.tgz",
"integrity": "sha512-dzW9kHxH011uBsidTXd14JXgzye/YLb2LzeKZ4bsgl/Knwx8AtbSFkkGxagdNOoh0DlqHCmfiEjWKBaqjOanVw==",
"requires": {
"array-back": "^3.0.1"
},
"dependencies": {
"array-back": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz",
"integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q=="
}
}
},
"ansi-escapes": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz",
"integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ=="
},
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"requires": {
"color-convert": "^1.9.0"
}
},
"array-back": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/array-back/-/array-back-2.0.0.tgz",
"integrity": "sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==",
"requires": {
"typical": "^2.6.1"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"builtins": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz",
"integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og="
},
"chalk": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
"integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
"requires": {
"ansi-styles": "^3.1.0",
"escape-string-regexp": "^1.0.5",
"supports-color": "^4.0.0"
}
},
"chardet": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
},
"cli-cursor": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
"integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
"requires": {
"restore-cursor": "^2.0.0"
}
},
"cli-width": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
"integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"command-line-args": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-4.0.7.tgz",
"integrity": "sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA==",
"requires": {
"array-back": "^2.0.0",
"find-replace": "^1.0.3",
"typical": "^2.6.1"
}
},
"command-line-commands": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/command-line-commands/-/command-line-commands-2.0.1.tgz",
"integrity": "sha512-m8c2p1DrNd2ruIAggxd/y6DgygQayf6r8RHwchhXryaLF8I6koYjoYroVP+emeROE9DXN5b9sP1Gh+WtvTTdtQ==",
"requires": {
"array-back": "^2.0.0"
}
},
"command-line-usage": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-4.1.0.tgz",
"integrity": "sha512-MxS8Ad995KpdAC0Jopo/ovGIroV/m0KHwzKfXxKag6FHOkGsH8/lv5yjgablcRxCJJC0oJeUMuO/gmaq+Wq46g==",
"requires": {
"ansi-escape-sequences": "^4.0.0",
"array-back": "^2.0.0",
"table-layout": "^0.4.2",
"typical": "^2.6.1"
}
},
"commander": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
"optional": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"external-editor": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
"requires": {
"chardet": "^0.4.0",
"iconv-lite": "^0.4.17",
"tmp": "^0.0.33"
}
},
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
"integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
"requires": {
"escape-string-regexp": "^1.0.5"
}
},
"find-replace": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/find-replace/-/find-replace-1.0.3.tgz",
"integrity": "sha1-uI5zZNLZyVlVnziMZmcNYTBEH6A=",
"requires": {
"array-back": "^1.0.4",
"test-value": "^2.1.0"
},
"dependencies": {
"array-back": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz",
"integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=",
"requires": {
"typical": "^2.6.0"
}
}
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"git-config": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/git-config/-/git-config-0.0.7.tgz",
"integrity": "sha1-qcij7wendsPXImE1bYtye2IgKyg=",
"requires": {
"iniparser": "~1.0.5"
}
},
"glob": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"handlebars": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz",
"integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==",
"requires": {
"neo-async": "^2.6.0",
"optimist": "^0.6.1",
"source-map": "^0.6.1",
"uglify-js": "^3.1.4"
}
},
"has-flag": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"iniparser": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/iniparser/-/iniparser-1.0.5.tgz",
"integrity": "sha1-g21r7+bfv87gvM8c+fKsxwJ/eD0="
},
"inquirer": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
"integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
"requires": {
"ansi-escapes": "^3.0.0",
"chalk": "^2.0.0",
"cli-cursor": "^2.1.0",
"cli-width": "^2.0.0",
"external-editor": "^2.0.4",
"figures": "^2.0.0",
"lodash": "^4.3.0",
"mute-stream": "0.0.7",
"run-async": "^2.2.0",
"rx-lite": "^4.0.8",
"rx-lite-aggregates": "^4.0.8",
"string-width": "^2.1.0",
"strip-ansi": "^4.0.0",
"through": "^2.3.6"
}
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
"integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
},
"jsonpath-rs": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/jsonpath-rs/-/jsonpath-rs-0.1.7.tgz",
"integrity": "sha512-BSuCWJK5PaTevsPHmFaLb9kzoc1Wh56+TBm6XH+gObIKA8Z3SQp6gUrgibGlApCYipha4IDo59StrdyVcvVPqA==",
"requires": {
"neon-cli": "^0.2.0"
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
},
"lodash.padend": {
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz",
"integrity": "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4="
},
"mimic-fn": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
}
}
},
"mute-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
},
"neo-async": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz",
"integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA=="
},
"neon-cli": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/neon-cli/-/neon-cli-0.2.0.tgz",
"integrity": "sha512-IsrxCyUcuAyWiq4Z+JnTXrjurj2SAL2VtWnCXS8iBYGJeIs1NIhFuLaM6fe7+rOyFfDcqUUTWGxZmkvUqwweRA==",
"requires": {
"chalk": "~2.1.0",
"command-line-args": "^4.0.2",
"command-line-commands": "^2.0.0",
"command-line-usage": "^4.0.0",
"git-config": "0.0.7",
"handlebars": "^4.0.3",
"inquirer": "^3.0.6",
"mkdirp": "^0.5.1",
"quickly-copy-file": "^1.0.0",
"rimraf": "^2.6.1",
"rsvp": "^4.6.1",
"semver": "^5.1.0",
"toml": "^2.3.0",
"ts-typed-json": "^0.2.2",
"validate-npm-package-license": "^3.0.1",
"validate-npm-package-name": "^3.0.0"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"onetime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
"integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
"requires": {
"mimic-fn": "^1.0.0"
}
},
"optimist": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
"requires": {
"minimist": "~0.0.1",
"wordwrap": "~0.0.2"
}
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"quickly-copy-file": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/quickly-copy-file/-/quickly-copy-file-1.0.0.tgz",
"integrity": "sha1-n4/wZiMFEO50IrASFHKwk6hpCFk=",
"requires": {
"mkdirp": "~0.5.0"
}
},
"reduce-flatten": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-1.0.1.tgz",
"integrity": "sha1-JYx479FT3fk8tWEjf2EYTzaW4yc="
},
"restore-cursor": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
"integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
"requires": {
"onetime": "^2.0.0",
"signal-exit": "^3.0.2"
}
},
"rimraf": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"requires": {
"glob": "^7.1.3"
}
},
"rsvp": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.4.tgz",
"integrity": "sha512-6FomvYPfs+Jy9TfXmBpBuMWNH94SgCsZmJKcanySzgNNP6LjWxBvyLTa9KaMfDDM5oxRfrKDB0r/qeRsLwnBfA=="
},
"run-async": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
"integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
"requires": {
"is-promise": "^2.1.0"
}
},
"rx-lite": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
"integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ="
},
"rx-lite-aggregates": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
"integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
"requires": {
"rx-lite": "*"
}
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
},
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"spdx-correct": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
"integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
"requires": {
"spdx-expression-parse": "^3.0.0",
"spdx-license-ids": "^3.0.0"
}
},
"spdx-exceptions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
"integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA=="
},
"spdx-expression-parse": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
"integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
"requires": {
"spdx-exceptions": "^2.1.0",
"spdx-license-ids": "^3.0.0"
}
},
"spdx-license-ids": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz",
"integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA=="
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
}
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"requires": {
"ansi-regex": "^3.0.0"
}
},
"supports-color": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
"integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
"requires": {
"has-flag": "^2.0.0"
}
},
"table-layout": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/table-layout/-/table-layout-0.4.4.tgz",
"integrity": "sha512-uNaR3SRMJwfdp9OUr36eyEi6LLsbcTqTO/hfTsNviKsNeyMBPICJCC7QXRF3+07bAP6FRwA8rczJPBqXDc0CkQ==",
"requires": {
"array-back": "^2.0.0",
"deep-extend": "~0.6.0",
"lodash.padend": "^4.6.1",
"typical": "^2.6.1",
"wordwrapjs": "^3.0.0"
}
},
"test-value": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz",
"integrity": "sha1-Edpv9nDzRxpztiXKTz/c97t0gpE=",
"requires": {
"array-back": "^1.0.3",
"typical": "^2.6.0"
},
"dependencies": {
"array-back": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz",
"integrity": "sha1-ZEun8JX3/898Q7Xw3DnTwfA8Bjs=",
"requires": {
"typical": "^2.6.0"
}
}
}
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"requires": {
"os-tmpdir": "~1.0.2"
}
},
"toml": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/toml/-/toml-2.3.6.tgz",
"integrity": "sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ=="
},
"ts-typed-json": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/ts-typed-json/-/ts-typed-json-0.2.2.tgz",
"integrity": "sha1-UxhL7ok+RZkbc8jEY6OLWeJ81H4=",
"requires": {
"rsvp": "^3.5.0"
},
"dependencies": {
"rsvp": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz",
"integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw=="
}
}
},
"typical": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/typical/-/typical-2.6.1.tgz",
"integrity": "sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0="
},
"uglify-js": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.4.tgz",
"integrity": "sha512-GpKo28q/7Bm5BcX9vOu4S46FwisbPbAmkkqPnGIpKvKTM96I85N6XHQV+k4I6FA2wxgLhcsSyHoNhzucwCflvA==",
"optional": true,
"requires": {
"commander": "~2.20.0",
"source-map": "~0.6.1"
}
},
"validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
"integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
"requires": {
"spdx-correct": "^3.0.0",
"spdx-expression-parse": "^3.0.0"
}
},
"validate-npm-package-name": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz",
"integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=",
"requires": {
"builtins": "^1.0.3"
}
},
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
},
"wordwrapjs": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-3.0.0.tgz",
"integrity": "sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==",
"requires": {
"reduce-flatten": "^1.0.1",
"typical": "^2.6.1"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}
}
}

View File

@ -0,0 +1,9 @@
{
"name": "jsonpath-rs-example",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"jsonpath-rs": "0"
}
}

2
examples/nodejs-wasm/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
dist

View File

@ -0,0 +1,31 @@
const jsonpath = require('jsonpath-wasm');
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let ret = [
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
];
let selector = new jsonpath.Selector();
selector.path('$..friends[0]');
selector.value(jsonObj);
let selectToObj = selector.selectTo();
let selectToString = selector.selectToStr();
console.log(
JSON.stringify(ret) == JSON.stringify(selectToObj),
JSON.stringify(ret) == selectToString
);

View File

@ -0,0 +1,9 @@
{
"name": "jsonpath-wasm-nodejs-example",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"jsonpath-wasm": "0"
}
}

View File

@ -2,7 +2,7 @@
[![Build Status](https://travis-ci.org/freestrings/jsonpath.svg?branch=master)](https://travis-ci.org/freestrings/jsonpath)
It is [JsonPath](https://goessner.net/articles/JsonPath/) implementation. The core implementation is written in Rust.
It is native-addon of [jsonpath_lib](https://github.com/freestrings/jsonpath) that is [JsonPath](https://goessner.net/articles/JsonPath/) engine written in Rust.
## Notice
@ -12,14 +12,51 @@ Build from source instead of using pre-built binary, and if Rust is not installe
> Not yet tested in Windows
## 목차
## APIs
* [jsonpath.select(json: string|object, jsonpath: string)](#json-stringobject-jsonpath-string)
* [jsonpath.compile(jsonpath: string)](#compilejsonpath-string)
* [jsonpath.selector(json: string|object)](#selectorjson-stringobject)
* [Simple time check](https://github.com/freestrings/jsonpath/wiki/Simple-timecheck-jsonpath-native)
* [jsonpath.Selector](#jsonpathselector)
* [jsonpath.select(json: string|object, jsonpath: string)](#jsonpathselectjson-stringobject-jsonpath-string)
* [jsonpath.compile(jsonpath: string)](#jsonpathcompilejsonpath-string)
* [jsonpath.selector(json: string|object)](#jsonpathselectorjson-stringobject)
* [Other Examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples)
### jsonpath.Selector
```javascript
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let selector = new jsonpath.Selector().value(jsonObj);
{
let jsonObj = selector.path('$..[?(@.age >= 30)]').selectTo();
let resultObj = [{"name": "친구3", "age": 30}];
console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj));
}
{
let jsonObj = selector.path('$..[?(@.age == 20)]').selectTo();
let resultObj = [{"name": "친구1", "age": 20}, {"name": "친구2", "age": 20}];
console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj));
}
{
let jsonObj = selector.value({"friends": [ {"name": "친구5", "age": 20} ]}).selectTo();
let resultObj = [{"name": "친구5", "age": 20}];
console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj));
}
```
### jsonpath.select(json: string|object, jsonpath: string)
```javascript

View File

@ -1,7 +1,7 @@
const { Compile, Selector, selectStr } = require('../native');
const { CompileFn, SelectorFn, selectStr, Selector: _Selector } = require('../native');
function compile(path) {
let compile = new Compile(path);
let compile = new CompileFn(path);
return (json) => {
if(typeof json != 'string') {
json = JSON.stringify(json)
@ -14,9 +14,9 @@ function selector(json) {
if(typeof json != 'string') {
json = JSON.stringify(json)
}
let selector = new Selector(json);
let selector = new SelectorFn(json);
return (path) => {
return JSON.parse(selector.selector(path));
return JSON.parse(selector.select(path));
}
}
@ -27,8 +27,38 @@ function select(json, path) {
return JSON.parse(selectStr(json, path));
}
class Selector {
constructor() {
this._selector = new _Selector();
return this;
}
path(path) {
this._selector.path(path);
return this;
}
value(json) {
if(typeof json != 'string') {
json = JSON.stringify(json)
}
this._selector.value_from_str(json);
return this;
}
selectToStr() {
return this._selector.select_to_str();
}
selectTo() {
return JSON.parse(this.selectToStr());
}
}
module.exports = {
compile,
selector,
select
select,
Selector
};

View File

@ -14,7 +14,7 @@ exclude = ["artifacts.json", "index.node"]
neon-build = "0.2.0"
[dependencies]
jsonpath_lib = "0.1.8"
jsonpath_lib = "0.1.9"
neon = "0.2.0"
neon-serde = "0.1.1"
serde_json = { version = "1.0", features = ["preserve_order"] }

View File

@ -4,13 +4,13 @@ extern crate neon;
extern crate neon_serde;
extern crate serde_json;
use std::ops::Deref;
use jsonpath::filter::value_filter::JsonValueFilter;
use jsonpath::parser::parser::{Node, NodeVisitor, Parser};
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
use jsonpath::Selector;
use neon::prelude::*;
use serde_json::Value;
use std::ops::Deref;
///
/// `neon_serde::from_value` has very poor performance.
@ -35,16 +35,20 @@ fn select_str(mut ctx: FunctionContext) -> JsResult<JsValue> {
}
}
pub struct Compile {
pub struct CompileFn {
node: Node
}
pub struct Selector {
pub struct SelectorFn {
json: RefValueWrapper
}
pub struct SelectorCls {
selector: Selector
}
declare_types! {
pub class JsCompile for Compile {
pub class JsCompileFn for CompileFn {
init(mut ctx) {
let path = ctx.argument::<JsString>(0)?.value();
let mut parser = Parser::new(path.as_str());
@ -54,7 +58,7 @@ declare_types! {
Err(e) => panic!("{:?}", e)
};
Ok(Compile { node })
Ok(CompileFn { node })
}
method template(mut ctx) {
@ -81,7 +85,7 @@ declare_types! {
}
}
pub class JsSelector for Selector {
pub class JsSelectorFn for SelectorFn {
init(mut ctx) {
let json_str = ctx.argument::<JsString>(0)?.value();
let ref_value: RefValue = match serde_json::from_str(&json_str) {
@ -89,10 +93,10 @@ declare_types! {
Err(e) => panic!("{:?}", e)
};
Ok(Selector { json: ref_value.into() })
Ok(SelectorFn { json: ref_value.into() })
}
method selector(mut ctx) {
method select(mut ctx) {
let this = ctx.this();
let json = {
@ -117,9 +121,55 @@ declare_types! {
}
}
}
pub class JsSelector for SelectorCls {
init(mut _ctx) {
Ok(SelectorCls { selector: Selector::new() })
}
method path(mut ctx) {
let mut this = ctx.this();
let path = ctx.argument::<JsString>(0)?.value();
{
let guard = ctx.lock();
let mut this = this.borrow_mut(&guard);
let _ = this.selector.path(&path);
}
Ok(JsUndefined::new().upcast())
}
method value_from_str(mut ctx) {
let mut this = ctx.this();
let json_str = ctx.argument::<JsString>(0)?.value();
{
let guard = ctx.lock();
let mut this = this.borrow_mut(&guard);
let _ = this.selector.value_from_str(&json_str);
}
Ok(JsUndefined::new().upcast())
}
method select_to_str(mut ctx) {
let mut this = ctx.this();
let result = {
let guard = ctx.lock();
let mut this = this.borrow_mut(&guard);
this.selector.select_to_str()
};
match result {
Ok(json_str) => Ok(JsString::new(&mut ctx, &json_str).upcast()),
Err(e) => panic!("{:?}", e)
}
}
}
}
register_module!(mut m, {
m.export_class::<JsCompile>("Compile").expect("Compile class error");
m.export_class::<JsCompileFn>("CompileFn").expect("CompileFn class error");
m.export_class::<JsSelectorFn>("SelectorFn").expect("SelectorFn class error");
m.export_class::<JsSelector>("Selector").expect("Selector class error");
m.export_function("select", select)?;
m.export_function("selectStr", select_str)?;

View File

@ -1,6 +1,6 @@
{
"name": "jsonpath-rs",
"version": "0.1.5",
"version": "0.1.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,15 +1,16 @@
{
"name": "jsonpath-rs",
"version": "0.1.6",
"version": "0.1.8",
"description": "It is JsonPath implementation. The core implementation is written in Rust",
"author": "Changseok Han <freestrings@gmail.com>",
"license": "MIT",
"keywords": [
"jsonpath",
"native-addon",
"rust-binding",
"rust",
"rustlang",
"json"
"json",
"parsing"
],
"main": "lib/index.js",
"dependencies": {

View File

@ -1,5 +1,360 @@
const jsonpath = require('../lib/index.js');
let jsonObj = {
"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
}
},
"expensive": 10
};
let list = {
'$.store.book[*].author': [
"Nigel Rees",
"Evelyn Waugh",
"Herman Melville",
"J. R. R. Tolkien"
],
'$..author':[
"Nigel Rees",
"Evelyn Waugh",
"Herman Melville",
"J. R. R. Tolkien"
],
'$.store.*': [
[
{
"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
}
],
{
"color": "red",
"price": 19.95
}
],
'$.store..price':[
8.95,
12.99,
8.99,
22.99,
19.95
],
'$..book[2]': [
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
}
],
'$..book[-2]': [
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
}
],
'$..book[0,1]': [
{
"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
}
],
'$..book[:2]': [
{
"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
}
],
'$..book[1:2]': [
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
}
],
'$..book[-2:]': [
{
"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
}
],
'$..book[2:]': [
{
"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
}
],
'$..book[?(@.isbn)]': [
{
"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
}
],
'$.store.book[?(@.price < 10)]': [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
}
],
'$..*': [
{
"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
}
},
10,
[
{
"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
}
],
{
"color": "red",
"price": 19.95
},
{
"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
},
"reference",
"Nigel Rees",
"Sayings of the Century",
8.95,
"fiction",
"Evelyn Waugh",
"Sword of Honour",
12.99,
"fiction",
"Herman Melville",
"Moby Dick",
"0-553-21311-3",
8.99,
"fiction",
"J. R. R. Tolkien",
"The Lord of the Rings",
"0-395-19395-8",
22.99,
"red",
19.95
],
'$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]': [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
}
]
};
describe('compile test', () => {
it('basic', (done) => {
let template = jsonpath.compile('$.a');
@ -30,70 +385,218 @@ describe('select test', () => {
});
describe('filter test', () => {
it('complex filter1', (done) => {
let json = {
'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,
},
},
'expensive': 10,
};
let target = [
{
category: 'fiction',
author: 'Evelyn Waugh',
title: 'Sword of Honour',
price: 12.99,
},
{
category: 'fiction',
author: 'J. R. R. Tolkien',
title: 'The Lord of the Rings',
isbn: '0-395-19395-8',
price: 22.99,
},
{
category: 'reference',
author: 'Nigel Rees',
title: 'Sayings of the Century',
price: 8.95,
}]
;
function run(done, path, expected) {
let result = jsonpath.select(jsonObj, path);
if (JSON.stringify(result) === JSON.stringify(expected)) {
done();
}
}
let result = jsonpath.select(json, '$..book[?((@.price == 12.99 || $.store.bicycle.price < @.price) || @.category == "reference")]');
if (JSON.stringify(result) === JSON.stringify(target)) {
for( var i in list ) {
it(i, (done) => {
run (done, i, list[i]);
})
}
});
describe('Selector test', () => {
it('basic selectTo', (done) => {
let result = new jsonpath.Selector().path('$.a').value({'a': 1}).selectTo();
if (result === 1) {
done();
}
});
it('basic selectToStr', (done) => {
let result = new jsonpath.Selector().path('$.a').value({'a': 1}).selectToStr();
if (result === '1') {
done();
}
});
it('select', (done) => {
let selector = new jsonpath.Selector().value(jsonObj);
for(var i in list) {
if(JSON.stringify(list[i]) !== selector.path(i).selectToStr()) {
throw `fail: ${i}`;
}
}
done();
});
});
describe('README test', () => {
it('jsonpath.Selector', (done) => {
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let selector = new jsonpath.Selector().value(jsonObj);
{
let jsonObj = selector.path('$..[?(@.age >= 30)]').selectTo();
let resultObj = [{"name": "친구3", "age": 30}];
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
throw 'jsonpath.Selector: $..[?(@.age >= 30)]';
}
}
{
let jsonObj = selector.path('$..[?(@.age == 20)]').selectTo();
let resultObj = [{"name": "친구1", "age": 20}, {"name": "친구2", "age": 20}];
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
throw 'jsonpath.Selector: $..[?(@.age >= 20)]';
}
}
{
let jsonObj = selector.value({"friends": [ {"name": "친구5", "age": 20} ]}).selectTo();
let resultObj = [{"name": "친구5", "age": 20}];
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
throw 'jsonpath.Selector: change value';
}
}
done();
});
it('jsonpath.select(json: string|object, jsonpath: string)', (done) => {
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let ret = [
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
];
let selectAsString = jsonpath.select(JSON.stringify(jsonObj), '$..friends[0]');
let selectAsObj = jsonpath.select(jsonObj, '$..friends[0]');
if(
JSON.stringify(ret) !== JSON.stringify(selectAsString) ||
JSON.stringify(ret) !== JSON.stringify(selectAsObj)
) {
throw 'jsonpath.select(json: string|object, jsonpath: string)';
}
done();
});
it('jsonpath.compile(jsonpath: string)', (done) => {
let template = jsonpath.compile('$..friends[0]');
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let ret = [
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
];
let selectAsString = template(JSON.stringify(jsonObj));
let selectAsObj = template(jsonObj);
if(
JSON.stringify(ret) !== JSON.stringify(selectAsString) ||
JSON.stringify(ret) !== JSON.stringify(selectAsObj)
) {
throw 'jsonpath.compile(jsonpath: string) 1';
}
let jsonObj2 = {
"school": {
"friends": [
{"name": "Millicent Norman"},
{"name": "Vincent Cannon"}
]
},
"friends": [ {"age": 30}, {"age": 40} ]
};
let ret2 = [
{"age": 30},
{"name": "Millicent Norman"}
];
let selectAsString2 = template(JSON.stringify(jsonObj2));
let selectAsObj2 = template(jsonObj2);
if(
JSON.stringify(ret2) !== JSON.stringify(selectAsString2) ||
JSON.stringify(ret2) !== JSON.stringify(selectAsObj2)
) {
throw 'jsonpath.compile(jsonpath: string) 2';
}
done();
});
it('jsonpath.selector(json: string|object)', (done) => {
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let ret1 = [
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
];
let ret2 = [
{"name": "친구4"},
{"name": "친구2", "age": 20}
];
let selector = jsonpath.selector(jsonObj);
let select1 = selector('$..friends[0]');
let select2 = selector('$..friends[1]');
if(
JSON.stringify(ret1) !== JSON.stringify(select1) ||
JSON.stringify(ret2) !== JSON.stringify(select2)
) {
throw 'jsonpath.selector(json: string|object)';
}
done();
});
});

View File

@ -6,8 +6,8 @@ use serde_json::Value;
use filter::term::*;
use filter::value_wrapper::*;
use parser::parser::{FilterToken, NodeVisitor, ParseToken};
use ref_value::model::*;
use parser::parser::{ParseToken, FilterToken, NodeVisitor};
trait ArrayIndex {
fn index(&self, v: &RefValueWrapper) -> usize;
@ -56,14 +56,14 @@ pub enum ValueFilterKey {
#[derive(Debug)]
pub struct ValueFilter {
vw: ValueWrapper,
val_wrapper: ValueWrapper,
last_key: Option<ValueFilterKey>,
filter_mode: bool,
}
impl ValueFilter {
pub fn new(v: RefValueWrapper, is_leaves: bool, filter_mode: bool) -> Self {
ValueFilter { vw: ValueWrapper::new(v, is_leaves), last_key: None, filter_mode }
ValueFilter { val_wrapper: ValueWrapper::new(v, is_leaves), last_key: None, filter_mode }
}
fn iter_to_value_vec<'a, I: Iterator<Item=&'a RefValueWrapper>>(iter: I) -> Vec<RefValueWrapper> {
@ -130,11 +130,11 @@ impl ValueFilter {
pub fn step_leaves_all(&mut self) -> &ValueWrapper {
debug!("step_leaves_all");
let mut buf = Vec::new();
Self::collect_all(None, &self.vw.get_val(), &mut buf);
Self::collect_all(None, &self.val_wrapper.get_val(), &mut buf);
trace!("step_leaves_all - {:?}", buf);
self.last_key = Some(ValueFilterKey::All);
self.vw = ValueWrapper::new(RefValue::Array(buf).into(), true);
&self.vw
self.val_wrapper = ValueWrapper::new(RefValue::Array(buf).into(), true);
&self.val_wrapper
}
pub fn step_leaves_str(&mut self, key: &str) -> &ValueWrapper {
@ -144,17 +144,17 @@ impl ValueFilter {
pub fn step_leaves_string(&mut self, key: &String) -> &ValueWrapper {
debug!("step_leaves_string");
let mut buf = Vec::new();
Self::collect_all(Some(key), &self.vw.get_val(), &mut buf);
Self::collect_all(Some(key), &self.val_wrapper.get_val(), &mut buf);
trace!("step_leaves_string - {:?}", buf);
self.last_key = Some(ValueFilterKey::String(key.clone()));
self.vw = ValueWrapper::new(RefValue::Array(buf).into(), true);
&self.vw
self.val_wrapper = ValueWrapper::new(RefValue::Array(buf).into(), true);
&self.val_wrapper
}
pub fn step_in_all(&mut self) -> &ValueWrapper {
debug!("step_in_all");
let vec = match self.vw.get_val().deref() {
let vec = match self.val_wrapper.get_val().deref() {
RefValue::Object(ref map) => {
Self::iter_to_value_vec(map.values())
}
@ -162,25 +162,25 @@ impl ValueFilter {
Self::iter_to_value_vec(list.iter())
}
RefValue::Null => Vec::new(),
_ => vec![self.vw.get_val().clone()]
_ => vec![self.val_wrapper.get_val().clone()]
};
self.last_key = Some(ValueFilterKey::All);
self.vw.replace(RefValue::Array(vec).into());
trace!("step_in_all - {:?}", self.vw.get_val());
&self.vw
self.val_wrapper.replace(RefValue::Array(vec).into());
trace!("step_in_all - {:?}", self.val_wrapper.get_val());
&self.val_wrapper
}
pub fn step_in_num(&mut self, key: &f64) -> &ValueWrapper {
debug!("step_in_num");
trace!("step_in_num - before: leaves {}, filterMode {} - {:?}"
, self.vw.is_leaves()
, self.val_wrapper.is_leaves()
, self.filter_mode
, self.vw.get_val());
, self.val_wrapper.get_val());
let v = if self.vw.is_leaves() {
let v = if self.val_wrapper.is_leaves() {
let filter_mode = self.filter_mode;
match self.vw.get_val().deref() {
match self.val_wrapper.get_val().deref() {
RefValue::Array(ref vec) => {
let mut ret = Vec::new();
for v in vec {
@ -191,16 +191,16 @@ impl ValueFilter {
}
RefValue::Array(ret).into()
}
_ => key.take_value(&self.vw.get_val())
_ => key.take_value(&self.val_wrapper.get_val())
}
} else {
key.take_value(&self.vw.get_val())
key.take_value(&self.val_wrapper.get_val())
};
self.last_key = Some(ValueFilterKey::Num(key.index(&v)));
self.vw.replace(v);
trace!("step_in_num - after: {:?}", self.vw.get_val());
&self.vw
self.val_wrapper.replace(v);
trace!("step_in_num - after: {:?}", self.val_wrapper.get_val());
&self.val_wrapper
}
pub fn step_in_str(&mut self, key: &str) -> &ValueWrapper {
@ -210,13 +210,13 @@ impl ValueFilter {
pub fn step_in_string(&mut self, key: &String) -> &ValueWrapper {
debug!("step_in_string");
trace!("step_in_string - before: {},{},{:?}"
, self.vw.is_leaves()
, self.val_wrapper.is_leaves()
, self.filter_mode
, self.vw.get_val());
, self.val_wrapper.get_val());
let filter_mode = self.filter_mode;
let is_leaves = self.vw.is_leaves();
let val = match self.vw.get_val().deref() {
let is_leaves = self.val_wrapper.is_leaves();
let val = match self.val_wrapper.get_val().deref() {
RefValue::Array(ref vec) if is_leaves => {
let mut buf = Vec::new();
for mut v in vec {
@ -230,6 +230,11 @@ impl ValueFilter {
}
}
buf.append(&mut ret);
} else if v.is_object() {
let nested_wrapper = Self::get_nested_object(v, key, filter_mode);
if !nested_wrapper.is_null() {
buf.push(nested_wrapper.clone());
}
} else {
match v.get(key.clone()) {
Some(v) => buf.push(v.clone()),
@ -251,7 +256,7 @@ impl ValueFilter {
RefValue::Array(ret).into()
}
_ => {
match self.vw.get_val().get(key.clone()) {
match self.val_wrapper.get_val().get(key.clone()) {
Some(v) => v.clone(),
_ => RefValue::Null.into()
}
@ -259,12 +264,12 @@ impl ValueFilter {
};
self.last_key = Some(ValueFilterKey::String(key.clone()));
self.vw.replace(val);
self.val_wrapper.replace(val);
trace!("step_in_string - after: {},{},{:?}"
, self.vw.is_leaves()
, self.val_wrapper.is_leaves()
, self.filter_mode
, self.vw.get_val());
&self.vw
, self.val_wrapper.get_val());
&self.val_wrapper
}
}
@ -279,7 +284,7 @@ impl JsonValueFilter {
pub fn new(json: &str) -> Result<Self, String> {
let json: RefValue = serde_json::from_str(json)
.map_err(|e| e.description().to_string())?;
Ok(JsonValueFilter::new_from_value(json .into()))
Ok(JsonValueFilter::new_from_value(json.into()))
}
pub fn new_from_value(json: RefValueWrapper) -> Self {
@ -303,7 +308,7 @@ impl JsonValueFilter {
if from_current {
self.filter_stack.last()
.map(|vf| {
ValueFilter::new(vf.vw.get_val().clone(), vf.vw.is_leaves(), from_current)
ValueFilter::new(vf.val_wrapper.get_val().clone(), vf.val_wrapper.is_leaves(), from_current)
})
.and_then(|vf| {
Some(self.filter_stack.push(vf))
@ -321,13 +326,13 @@ impl JsonValueFilter {
} else {
match self.filter_stack.last_mut() {
Some(vf) => {
vf.vw.set_leaves(is_leaves);
vf.val_wrapper.set_leaves(is_leaves);
if v.is_null() {
vf.vw.replace(v);
vf.val_wrapper.replace(v);
} else if v.is_array() && v.as_array().unwrap().is_empty() {
vf.vw.replace(RefValue::Null.into());
} else if vf.vw.is_array() {
vf.vw.replace(v);
vf.val_wrapper.replace(RefValue::Null.into());
} else if vf.val_wrapper.is_array() {
vf.val_wrapper.replace(v);
}
}
_ => {}
@ -337,14 +342,14 @@ impl JsonValueFilter {
pub fn into_value(&self) -> Value {
match self.filter_stack.last() {
Some(v) => v.vw.into_value(),
Some(v) => v.val_wrapper.into_value(),
_ => Value::Null
}
}
pub fn take_value(&mut self) -> RefValueWrapper {
match self.filter_stack.last_mut() {
Some(v) => v.vw.get_val().clone(),
Some(v) => v.val_wrapper.get_val().clone(),
_ => RefValue::Null.into()
}
}
@ -353,9 +358,9 @@ impl JsonValueFilter {
self.token_stack.pop();
match self.filter_stack.last_mut() {
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
Some(ref mut vf) if vf.val_wrapper.is_array() && vf.val_wrapper.is_leaves() => {
let mut ret = Vec::new();
if let RefValue::Array(val) = vf.vw.get_val().deref() {
if let RefValue::Array(val) = vf.val_wrapper.get_val().deref() {
for mut v in val {
for i in &indices {
let v = i.take_value(v);
@ -365,17 +370,17 @@ impl JsonValueFilter {
}
}
}
vf.vw.replace(RefValue::Array(ret).into());
vf.val_wrapper.replace(RefValue::Array(ret).into());
}
Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => {
Some(ref mut vf) if vf.val_wrapper.is_array() && !vf.val_wrapper.is_leaves() => {
let mut ret = Vec::new();
for i in indices {
let wrapper = i.take_value(&vf.vw.get_val());
let wrapper = i.take_value(&vf.val_wrapper.get_val());
if !wrapper.is_null() {
ret.push(wrapper.clone());
}
}
vf.vw.replace(RefValue::Array(ret).into());
vf.val_wrapper.replace(RefValue::Array(ret).into());
}
_ => {}
}
@ -413,21 +418,21 @@ impl JsonValueFilter {
}
match self.filter_stack.last_mut() {
Some(ref mut vf) if vf.vw.is_array() && vf.vw.is_leaves() => {
Some(ref mut vf) if vf.val_wrapper.is_array() && vf.val_wrapper.is_leaves() => {
let mut buf = Vec::new();
if let RefValue::Array(vec) = vf.vw.get_val().deref() {
if let RefValue::Array(vec) = vf.val_wrapper.get_val().deref() {
for mut v in vec {
let (from, to) = _from_to(from, to, v);
let mut v: Vec<RefValueWrapper> = _range(from, to, v);
buf.append(&mut v);
}
}
vf.vw.replace(RefValue::Array(buf).into());
vf.val_wrapper.replace(RefValue::Array(buf).into());
}
Some(ref mut vf) if vf.vw.is_array() && !vf.vw.is_leaves() => {
let (from, to) = _from_to(from, to, &vf.vw.get_val());
let vec: Vec<RefValueWrapper> = _range(from, to, vf.vw.get_val());
vf.vw.replace(RefValue::Array(vec).into());
Some(ref mut vf) if vf.val_wrapper.is_array() && !vf.val_wrapper.is_leaves() => {
let (from, to) = _from_to(from, to, &vf.val_wrapper.get_val());
let vec: Vec<RefValueWrapper> = _range(from, to, vf.val_wrapper.get_val());
vf.val_wrapper.replace(RefValue::Array(vec).into());
}
_ => {}
}
@ -491,13 +496,13 @@ impl JsonValueFilter {
_ => {
match self.filter_stack.pop() {
Some(mut vf) => {
let is_leaves = vf.vw.is_leaves();
match vf.vw.get_val().deref() {
let is_leaves = vf.val_wrapper.is_leaves();
match vf.val_wrapper.get_val().deref() {
RefValue::Null | RefValue::Bool(false) => {
self.replace_filter_stack(RefValue::Null.into(), is_leaves);
}
_ => {
self.replace_filter_stack(vf.vw.get_val().clone(), is_leaves);
self.replace_filter_stack(vf.val_wrapper.get_val().clone(), is_leaves);
}
}
}
@ -548,8 +553,13 @@ impl NodeVisitor for JsonValueFilter {
self.push_value_filter(ParseToken::Relative == token);
}
ParseToken::In
| ParseToken::Leaves
| ParseToken::Array => {
| ParseToken::Leaves => {
self.token_stack.push(token);
}
ParseToken::Array => {
if let Some(ParseToken::Leaves) = self.token_stack.last() {
self.token_all();
}
self.token_stack.push(token);
}
ParseToken::ArrayEof => {
@ -593,7 +603,7 @@ impl NodeVisitor for JsonValueFilter {
if self.token_stack.is_empty() && self.filter_stack.len() > 1 {
match self.filter_stack.pop() {
Some(vf) => {
self.term_stack.push(TermContext::Json(vf.last_key, vf.vw));
self.term_stack.push(TermContext::Json(vf.last_key, vf.val_wrapper));
}
_ => {}
}

View File

@ -79,15 +79,15 @@ impl ValueWrapper {
match self.val.deref() {
RefValue::Array(vec) => {
let mut ret = Vec::new();
let mut set = IndexSet::new();
for v in vec {
if _filter_with_object(v, key, |vv| {
Self::cmp_with_term(vv, et, cmp, false, reverse)
}) {
ret.push(v.clone());
set.insert(v.clone());
}
}
let ret = set.into_iter().collect();
Some(ValueWrapper::new(RefValue::Array(ret).into(), false))
}
_ => None
@ -109,12 +109,13 @@ impl ValueWrapper {
_ => {
match &(*self.val) {
RefValue::Array(vec) => {
let mut ret = Vec::new();
let mut set = IndexSet::new();
for v in vec {
if Self::cmp_with_term(v, et, &cmp, false, reverse) {
ret.push(v.clone());
set.insert(v.clone());
}
}
let ret = set.into_iter().collect();
ValueWrapper::new(RefValue::Array(ret).into(), false)
}
_ => {

View File

@ -158,6 +158,7 @@
//! assert_eq!(ret, json);
//! ```
extern crate core;
extern crate env_logger;
extern crate indexmap;
#[macro_use]
@ -166,40 +167,23 @@ extern crate log;
extern crate serde;
extern crate serde_json;
use std::error::Error;
use std::ops::Deref;
use core::borrow::BorrowMut;
use std::result;
use serde_json::Value;
use filter::value_filter::JsonValueFilter;
use parser::parser::{NodeVisitor, Parser};
use ref_value::model::RefValueWrapper;
#[doc(hidden)]
pub mod parser;
#[doc(hidden)]
pub mod filter;
#[doc(hidden)]
pub mod ref_value;
#[doc(hidden)]
pub mod select;
fn query_from_str(json: &str, path: &str) -> result::Result<JsonValueFilter, String> {
let mut jf = JsonValueFilter::new(json)?;
let mut parser = Parser::new(path);
parser.parse(&mut jf)?;
Ok(jf)
}
pub use select::Selector;
fn query_from_json_wrapper(json_wrapper: RefValueWrapper, path: &str) -> result::Result<JsonValueFilter, String> {
let mut jf = JsonValueFilter::new_from_value(json_wrapper);
let mut parser = Parser::new(path);
parser.parse(&mut jf)?;
Ok(jf)
}
/// It is a highorder function that compile a JsonPath then returns a function.
///
/// this return function can be reused for different JsonObjects.
/// It is a high-order function. it compile a JsonPath and then returns a function. this return-function can be reused for different JsonObjects.
///
/// ```rust
/// extern crate jsonpath_lib as jsonpath;
@ -227,23 +211,17 @@ fn query_from_json_wrapper(json_wrapper: RefValueWrapper, path: &str) -> result:
/// assert_eq!(json, ret);
/// ```
pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> result::Result<Value, String> + 'a {
let mut parser = Parser::new(path);
let node = parser.compile();
let mut selector = select::Selector::new();
let _ = selector.path(path);
let mut selector = Box::new(selector);
move |json| {
match &node {
Ok(n) => {
let mut jf = JsonValueFilter::new_from_value(json.into());
jf.visit(n.clone());
Ok((&jf.take_value()).into())
}
Err(e) => Err(e.clone())
}
let s: &mut select::Selector = selector.borrow_mut();
let _ = s.value(json.into());
s.select_to_value()
}
}
/// It returns highorder function that return a function.
///
/// this function has a jsonpath as argument and return a serde_json::value::Value. so you can use different JsonPath for one JsonObject.
/// It is a high-order function that return a function. this return-function has a jsonpath as argument and return a serde_json::value::Value. so you can use different JsonPath for one JsonObject.
///
/// ```rust
/// extern crate jsonpath_lib as jsonpath;
@ -277,17 +255,17 @@ pub fn compile<'a>(path: &'a str) -> impl FnMut(&Value) -> result::Result<Value,
/// ]);
/// assert_eq!(json, ret);
/// ```
pub fn selector(json: &Value) -> impl FnMut(&str) -> result::Result<Value, String> {
let wrapper: RefValueWrapper = json.into();
move |path: &str| {
let mut jf = query_from_json_wrapper(wrapper.clone(), path)?;
Ok((&jf.take_value()).into())
pub fn selector<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result<Value, String> {
let mut selector = select::Selector::new();
let _ = selector.value(json.into());
let mut selector = Box::new(selector);
move |path: &'a str| {
let s: &mut select::Selector = selector.borrow_mut();
s.path(path)?.select_to_value()
}
}
/// It returns highorder function that returns a function.
///
/// this function has a jsonpath as argument and return a serde::Deserialize. so you can use different JsonPath for one JsonObject.
/// It is a high-order function that returns a function. this return-function has a jsonpath as argument and return a serde::Deserialize. so you can use different JsonPath for one JsonObject.
///
/// ```rust
/// extern crate jsonpath_lib as jsonpath;
@ -331,19 +309,19 @@ pub fn selector(json: &Value) -> impl FnMut(&str) -> result::Result<Value, Strin
/// assert_eq!(json, ret);
/// ```
pub fn selector_as<T: serde::de::DeserializeOwned>(json: &Value) -> impl FnMut(&str) -> result::Result<T, String> {
let wrapper: RefValueWrapper = json.into();
let mut selector = select::Selector::new();
let _ = selector.value(json.into());
move |path: &str| {
let mut jf = query_from_json_wrapper(wrapper.clone(), path)?;
T::deserialize(jf.take_value().deref()).map_err(|e| format!("{:?}", e))
selector.path(path)?.select_to()
}
}
#[deprecated(since = "0.1.4", note = "Please use the selector function instead")]
pub fn reader(json: &Value) -> impl FnMut(&str) -> result::Result<Value, String> {
pub fn reader<'a>(json: &Value) -> impl FnMut(&'a str) -> result::Result<Value, String> {
selector(json)
}
/// Select a JsonObject. it return a serde_json::value::Value.
/// This function compile a jsonpath everytime and it convert `serde_json's Value` to `jsonpath's RefValue` everytime and then it return a `serde_json::value::Value`.
///
/// ```rust
/// extern crate jsonpath_lib as jsonpath;
@ -370,8 +348,8 @@ pub fn reader(json: &Value) -> impl FnMut(&str) -> result::Result<Value, String>
/// assert_eq!(json, ret);
/// ```
pub fn select(json: &Value, path: &str) -> result::Result<Value, String> {
let mut jf = query_from_json_wrapper(json.into(), path)?;
Ok((&jf.take_value()).into())
let mut selector = select::Selector::new();
selector.path(path)?.value(json.into())?.select_to_value()
}
#[deprecated(since = "0.1.4", note = "Please use the select function instead")]
@ -384,7 +362,7 @@ pub fn select_str(json: &str, path: &str) -> result::Result<String, String> {
select_as_str(json, path)
}
/// Select a JsonObject. it return a JsonObject as String.
/// This function compile a jsonpath everytime and it convert `&str` to `jsonpath's RefValue` everytime and then it return a json string.
///
/// ```rust
/// extern crate jsonpath_lib as jsonpath;
@ -408,11 +386,13 @@ pub fn select_str(json: &str, path: &str) -> result::Result<String, String> {
/// assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#);
/// ```
pub fn select_as_str(json: &str, path: &str) -> result::Result<String, String> {
let mut jf = query_from_str(json, path)?;
serde_json::to_string(&jf.take_value().deref()).map_err(|e| e.description().to_string())
select::Selector::new()
.path(path)?
.value_from_str(json)?
.select_to_str()
}
/// Select a JsonObject. it return a deserialized instance of type `T`
/// This function compile a jsonpath everytime and it convert `&str` to `jsonpath's RefValue` everytime and then it return a deserialized-instance of type `T`.
///
/// ```rust
/// extern crate jsonpath_lib as jsonpath;
@ -451,6 +431,8 @@ pub fn select_as_str(json: &str, path: &str) -> result::Result<String, String> {
/// assert_eq!(person, ret);
/// ```
pub fn select_as<T: serde::de::DeserializeOwned>(json: &str, path: &str) -> result::Result<T, String> {
let mut jf = query_from_str(json, path)?;
T::deserialize(jf.take_value().deref()).map_err(|e| e.description().to_string())
select::Selector::new()
.path(path)?
.value_from_str(json)?
.select_to()
}

View File

@ -245,6 +245,15 @@ impl Into<RefValueWrapper> for RefValue {
}
}
impl Into<RefValue> for &Value {
fn into(self) -> RefValue {
match self.serialize(super::ser::Serializer) {
Ok(v) => v,
Err(e) => panic!("Error Value into RefValue: {:?}", e)
}
}
}
impl Into<RefValueWrapper> for &Value {
fn into(self) -> RefValueWrapper {
match self.serialize(super::ser::Serializer) {

152
src/select/mod.rs Normal file
View File

@ -0,0 +1,152 @@
use std::ops::Deref;
use std::result;
use serde_json::Value;
use super::filter::value_filter::*;
use super::parser::parser::*;
use super::ref_value::model::*;
/// Utility. Functions like jsonpath::selector or jsonpath::compile are also implemented using this structure.
///
/// ```rust
/// extern crate jsonpath_lib as jsonpath;
/// extern crate serde;
/// extern crate serde_json;
///
/// use serde::{Deserialize, Serialize};
/// use serde_json::Value;
///
/// use jsonpath::Selector;
///
/// #[derive(Serialize, Deserialize, PartialEq, Debug)]
/// struct Person {
/// name: String,
/// age: u8,
/// phone: String,
/// }
///
/// fn input_str() -> &'static str {
/// r#"[
/// {
/// "name": "이름1",
/// "age": 40,
/// "phone": "+33 12341234"
/// },
/// {
/// "name": "이름2",
/// "age": 42,
/// "phone": "++44 12341234"
/// }
/// ]"#
/// }
///
/// fn input_json() -> Value {
/// serde_json::from_str(input_str()).unwrap()
/// }
///
/// fn input_person() -> Vec<Person> {
/// serde_json::from_str(input_str()).unwrap()
/// }
///
///
/// let mut selector = Selector::new();
///
/// let result = selector
/// .path("$..[?(@.age > 40)]").unwrap()
/// .value_from_str(input_str()).unwrap()
/// .select_to_value().unwrap();
/// assert_eq!(input_json()[1], result[0]);
///
/// let result = selector.select_to_str().unwrap();
/// assert_eq!(serde_json::to_string(&vec![&input_json()[1].clone()]).unwrap(), result);
///
/// let result = selector.select_to::<Vec<Person>>().unwrap();
/// assert_eq!(input_person()[1], result[0]);
///
/// let _ = selector.path("$..[?(@.age == 40)]");
///
/// let result = selector.select_to_value().unwrap();
/// assert_eq!(input_json()[0], result[0]);
///
/// let result = selector.select_to_str().unwrap();
/// assert_eq!(serde_json::to_string(&vec![&input_json()[0].clone()]).unwrap(), result);
///
/// let result = selector.select_to::<Vec<Person>>().unwrap();
/// assert_eq!(input_person()[0], result[0]);
/// ```
pub struct Selector {
pub(crate) node: Option<Node>,
pub(crate) value: Option<RefValueWrapper>,
}
impl Selector {
pub fn new() -> Self {
Selector { node: None, value: None }
}
pub fn path(&mut self, path: &str) -> result::Result<&mut Self, String> {
let mut parser = Parser::new(path);
self.node = Some(parser.compile()?);
Ok(self)
}
pub fn value(&mut self, ref_value: RefValue) -> result::Result<&mut Self, String> {
self.value = Some(ref_value.into());
Ok(self)
}
pub fn value_from(&mut self, serializable: &impl serde::ser::Serialize) -> result::Result<&mut Self, String> {
let ref_value: RefValue = serializable
.serialize(super::ref_value::ser::Serializer)
.map_err(|e| format!("{:?}", e))?;
self.value(ref_value)
}
pub fn value_from_str(&mut self, json_str: &str) -> result::Result<&mut Self, String> {
let ref_value: RefValue = serde_json::from_str(json_str)
.map_err(|e| format!("{:?}", e))?;
self.value(ref_value)
}
fn jf(&mut self) -> result::Result<JsonValueFilter, String> {
match &self.value {
Some(v) => Ok(JsonValueFilter::new_from_value(v.clone())),
_ => return Err("Value is empty".to_owned())
}
}
pub fn select_to_str(&mut self) -> result::Result<String, String> {
let mut jf = self.jf()?;
match &mut self.node {
Some(node) => {
jf.visit(node.clone());
return serde_json::to_string(jf.take_value().deref()).map_err(|e| format!("{:?}", e));
}
_ => return Err("Path is empty".to_owned())
};
}
pub fn select_to_value(&mut self) -> result::Result<Value, String> {
let mut jf = self.jf()?;
match &mut self.node {
Some(node) => {
jf.visit(node.clone());
Ok((&jf.take_value()).into())
}
_ => Err("Path is empty".to_owned())
}
}
pub fn select_to<T: serde::de::DeserializeOwned>(&mut self) -> result::Result<T, String> {
let mut jf = self.jf()?;
match &mut self.node {
Some(node) => {
jf.visit(node.clone());
T::deserialize(jf.take_value().deref()).map_err(|e| format!("{:?}", e))
}
_ => Err("Path is empty".to_owned())
}
}
}

View File

@ -201,6 +201,36 @@ fn op_default() {
let jf = do_filter("$..book[?( (@.price == 12.99 || @.category == 'reference') && @.price > 10)].price", "./benches/example.json");
let friends = json!([12.99]);
assert_eq!(friends, jf.into_value());
let ref value = json!([
{ "name": "이름1", "age": 40, "phone": "+33 12341234" },
{ "name": "이름2", "age": 42, "phone": "++44 12341234" }
]);
let mut jf = JsonValueFilter::new_from_value(value.into());
let mut parser = Parser::new("$..[?(@.age > 40)]");
parser.parse(&mut jf).unwrap();
let friends = json!([
{ "name" : "이름2", "age" : 42, "phone" : "++44 12341234" }
]);
assert_eq!(friends, jf.into_value());
let ref value = json!({
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]});
let mut jf = JsonValueFilter::new_from_value(value.into());
let mut parser = Parser::new("$..[?(@.age >= 30)]");
parser.parse(&mut jf).unwrap();
let friends = json!([{ "name" : "친구3", "age" : 30 }]);
assert_eq!(friends, jf.into_value());
}
#[test]

92
tests/selector.rs Normal file
View File

@ -0,0 +1,92 @@
extern crate jsonpath_lib as jsonpath;
extern crate serde;
extern crate serde_json;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use jsonpath::Selector;
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Person {
name: String,
age: u8,
phone: String,
}
fn input_str() -> &'static str {
r#"[
{
"name": "이름1",
"age": 40,
"phone": "+33 12341234"
},
{
"name": "이름2",
"age": 42,
"phone": "++44 12341234"
}
]"#
}
fn input_json() -> Value {
serde_json::from_str(input_str()).unwrap()
}
fn input_person() -> Vec<Person> {
serde_json::from_str(input_str()).unwrap()
}
#[test]
fn selector_value_from() {
let result = Selector::new()
.path("$..[?(@.age > 40)]").unwrap()
.value_from(&input_person()).unwrap()
.select_to::<Vec<Person>>().unwrap();
assert_eq!(input_person()[1], result[0]);
}
#[test]
fn selector_value() {
let result = Selector::new()
.path("$..[?(@.age > 40)]").unwrap()
.value((&input_json()).into()).unwrap()
.select_to_value().unwrap();
assert_eq!(input_json()[1], result[0]);
}
#[test]
fn selector_value_from_str() {
let result = Selector::new()
.path("$..[?(@.age > 40)]").unwrap()
.value_from_str(input_str()).unwrap()
.select_to_value().unwrap();
assert_eq!(input_json()[1], result[0]);
}
#[test]
fn selector_select_to() {
let mut selector = Selector::new();
let result = selector
.path("$..[?(@.age > 40)]").unwrap()
.value_from_str(input_str()).unwrap()
.select_to_value().unwrap();
assert_eq!(input_json()[1], result[0]);
let result = selector.select_to_str().unwrap();
assert_eq!(serde_json::to_string(&vec![&input_json()[1].clone()]).unwrap(), result);
let result = selector.select_to::<Vec<Person>>().unwrap();
assert_eq!(input_person()[1], result[0]);
let _ = selector.path("$..[?(@.age == 40)]");
let result = selector.select_to_value().unwrap();
assert_eq!(input_json()[0], result[0]);
let result = selector.select_to_str().unwrap();
assert_eq!(serde_json::to_string(&vec![&input_json()[0].clone()]).unwrap(), result);
let result = selector.select_to::<Vec<Person>>().unwrap();
assert_eq!(input_person()[0], result[0]);
}

4
wasm/.gitignore vendored
View File

@ -2,7 +2,9 @@ target
**/*.rs.bk
Cargo.lock
bin/
pkg/
browser_pkg
nodejs_pkg
all_pkg
wasm-pack.log
.idea/*
.vscode

View File

@ -1,9 +1,9 @@
[package]
name = "jsonpath-wasm"
version = "0.1.6"
version = "0.1.2"
authors = ["Changseok Han <freestrings@gmail.com>"]
description = "JsonPath Webassembly version compiled by Rust - Demo: https://freestrings.github.io/jsonpath"
keywords = ["library", "jsonpath", "json", "webassembly"]
description = "It is Webassembly version of jsonpath_lib that is JsonPath engine written in Rust - Demo: https://freestrings.github.io/jsonpath"
keywords = ["jsonpath", "json", "webassembly", "parsing", "rust"]
repository = "https://github.com/freestrings/jsonpath"
license = "MIT"
@ -26,6 +26,9 @@ web-sys = { version = "0.3", features = ['console'] }
[dev-dependencies]
wasm-bindgen-test = "0.2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
js-sys = "0.3"
[profile.release]
opt-level = "s"

183
wasm/README.md Normal file
View File

@ -0,0 +1,183 @@
# jsonpath-wasm
[![Build Status](https://travis-ci.org/freestrings/jsonpath.svg?branch=master)](https://travis-ci.org/freestrings/jsonpath)
It is Webassembly version of [jsonpath_lib](https://github.com/freestrings/jsonpath) that is [JsonPath](https://goessner.net/articles/JsonPath/) engine written in Rust.
## APIs
* [jsonpath.Selector](#jsonpathselector)
* [jsonpath.select(json: string|object, jsonpath: string)](#jsonpathselectjson-stringobject-jsonpath-string)
* [jsonpath.compile(jsonpath: string)](#jsonpathcompilejsonpath-string)
* [jsonpath.selector(json: string|object)](#jsonpathselectorjson-stringobject)
* [Other Examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples)
### jsonpath.Selector
```javascript
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let selector = new jsonpath.Selector().value(jsonObj);
{
let jsonObj = selector.path('$..[?(@.age >= 30)]').selectTo();
let resultObj = [{"name": "친구3", "age": 30}];
console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj));
}
{
let jsonObj = selector.path('$..[?(@.age == 20)]').selectTo();
let resultObj = [{"name": "친구1", "age": 20}, {"name": "친구2", "age": 20}];
console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj));
}
{
let jsonObj = selector.value({"friends": [ {"name": "친구5", "age": 20} ]}).selectTo();
let resultObj = [{"name": "친구5", "age": 20}];
console.log(JSON.stringify(jsonObj) === JSON.stringify(resultObj));
}
```
### jsonpath.select(json: string|object, jsonpath: string)
```javascript
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let ret = [
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
];
let selectAsString = jsonpath.select(JSON.stringify(jsonObj), '$..friends[0]');
let selectAsObj = jsonpath.select(jsonObj, '$..friends[0]');
console.log(
JSON.stringify(ret) == JSON.stringify(selectAsString),
JSON.stringify(ret) == JSON.stringify(selectAsObj)
);
// => true, true
```
### jsonpath.compile(jsonpath: string)
```javascript
let template = jsonpath.compile('$..friends[0]');
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let ret = [
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
];
let selectAsString = template(JSON.stringify(jsonObj));
let selectAsObj = template(jsonObj);
console.log(
JSON.stringify(ret) == JSON.stringify(selectAsString),
JSON.stringify(ret) == JSON.stringify(selectAsObj)
);
// => true, true
let jsonObj2 = {
"school": {
"friends": [
{"name": "Millicent Norman"},
{"name": "Vincent Cannon"}
]
},
"friends": [ {"age": 30}, {"age": 40} ]
};
let ret2 = [
{"age": 30},
{"name": "Millicent Norman"}
];
let selectAsString2 = template(JSON.stringify(jsonObj2));
let selectAsObj2 = template(jsonObj2);
console.log(
JSON.stringify(ret2) == JSON.stringify(selectAsString2),
JSON.stringify(ret2) == JSON.stringify(selectAsObj2)
);
// => true, true
```
### jsonpath.selector(json: string|object)
```javascript
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let ret1 = [
{"name": "친구3", "age": 30},
{"name": "친구1", "age": 20}
];
let ret2 = [
{"name": "친구4"},
{"name": "친구2", "age": 20}
];
let selector = jsonpath.selector(jsonObj);
// or as json string
// let selector = jsonpath.selector(JSON.stringify(jsonObj));
let select1 = selector('$..friends[0]');
let select2 = selector('$..friends[1]');
console.log(
JSON.stringify(ret1) == JSON.stringify(select1),
JSON.stringify(ret2) == JSON.stringify(select2)
);
// => true, true
```

View File

@ -7,19 +7,18 @@ extern crate wasm_bindgen;
extern crate web_sys;
use std::collections::HashMap;
use std::ops::Deref;
use std::result;
use std::result::Result;
use std::sync::Mutex;
use cfg_if::cfg_if;
use serde_json::Value;
use wasm_bindgen::prelude::*;
use web_sys::console;
use jsonpath::filter::value_filter::JsonValueFilter;
use jsonpath::parser::parser::{Node, NodeVisitor, Parser};
use jsonpath::ref_value::model::{RefValue, RefValueWrapper};
mod utils;
use jsonpath::Selector as _Selector;
use wasm_bindgen::prelude::*;
use web_sys::console;
cfg_if! {
if #[cfg(feature = "wee_alloc")] {
@ -29,11 +28,21 @@ cfg_if! {
}
}
cfg_if! {
if #[cfg(feature = "console_error_panic_hook")] {
extern crate console_error_panic_hook;
pub use self::console_error_panic_hook::set_once as set_panic_hook;
} else {
#[inline]
pub fn set_panic_hook() {}
}
}
fn filter_ref_value(json: RefValueWrapper, node: Node) -> JsValue {
let mut jf = JsonValueFilter::new_from_value(json);
jf.visit(node);
let taken: Value = (&jf.take_value()).into();
match JsValue::from_serde(&taken) {
let taken = &jf.take_value();
match JsValue::from_serde(taken.deref()) {
Ok(js_value) => js_value,
Err(e) => JsValue::from_str(&format!("Json deserialize error: {:?}", e))
}
@ -77,8 +86,8 @@ lazy_static! {
static ref CACHE_JSON_IDX: Mutex<usize> = Mutex::new(0);
}
#[wasm_bindgen]
pub fn alloc_json(js_value: JsValue) -> usize {
#[wasm_bindgen(js_name = allocJson)]
pub extern fn alloc_json(js_value: JsValue) -> usize {
match into_serde_json(&js_value) {
Ok(json) => {
let mut map = CACHE_JSON.lock().unwrap();
@ -98,8 +107,8 @@ pub fn alloc_json(js_value: JsValue) -> usize {
}
}
#[wasm_bindgen]
pub fn dealloc_json(ptr: usize) -> bool {
#[wasm_bindgen(js_name = deallocJson)]
pub extern fn dealloc_json(ptr: usize) -> bool {
let mut map = CACHE_JSON.lock().unwrap();
map.remove(&ptr).is_some()
}
@ -120,14 +129,6 @@ pub fn compile(path: &str) -> JsValue {
ret
}
///
/// deprecated. use selector
///
#[wasm_bindgen]
pub fn reader(js_value: JsValue) -> JsValue {
selector(js_value)
}
#[wasm_bindgen]
pub fn selector(js_value: JsValue) -> JsValue {
let json = match js_value.as_f64() {
@ -168,12 +169,54 @@ pub fn select(js_value: JsValue, path: &str) -> JsValue {
}
///
/// deprecated. use select
/// `wasm_bindgen` 제약으로 builder-pattern을 구사 할 수 없다.
///
#[wasm_bindgen]
pub fn read(js_value: JsValue, path: &str) -> JsValue {
select(js_value, path)
pub struct Selector {
selector: _Selector
}
#[wasm_bindgen]
pub fn testa() {}
impl Selector {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Selector { selector: _Selector::new() }
}
#[wasm_bindgen(catch)]
pub fn path(&mut self, path: &str) -> result::Result<(), JsValue> {
let _ = self.selector.path(path)?;
Ok(())
}
#[wasm_bindgen(catch)]
pub fn value(&mut self, value: JsValue) -> result::Result<(), JsValue> {
let ref_value = into_serde_json(&value)?;
let _ = self.selector.value(ref_value)?;
Ok(())
}
#[wasm_bindgen(catch, js_name = selectToStr)]
pub fn select_to_str(&mut self) -> result::Result<JsValue, JsValue> {
let json_str = self.selector.select_to_str()?;
Ok(JsValue::from_str(&json_str))
}
#[wasm_bindgen(catch, js_name = selectTo)]
pub fn select_to(&mut self) -> result::Result<JsValue, JsValue> {
let ref_value = self.selector.select_to::<RefValue>()
.map_err(|e| JsValue::from_str(&e))?;
Ok(JsValue::from_serde(&ref_value)
.map_err(|e| JsValue::from_str(&format!("{:?}", e)))?)
}
}
#[wasm_bindgen(catch)]
pub fn testa(js_value: JsValue, path: &str, iter: usize) -> result::Result<(), JsValue> {
for _ in 0..iter {
let mut parser = Parser::new(path);
let node = parser.compile().unwrap();
into_ref_value(&js_value, node);
}
Ok(())
}

View File

@ -1,11 +0,0 @@
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "console_error_panic_hook")] {
extern crate console_error_panic_hook;
pub use self::console_error_panic_hook::set_once as set_panic_hook;
} else {
#[inline]
pub fn set_panic_hook() {}
}
}

View File

@ -1,13 +1,118 @@
//! Test suite for the Web and headless browsers.
#![cfg(target_arch = "wasm32")]
extern crate core;
extern crate js_sys;
extern crate jsonpath_wasm as jsonpath;
#[macro_use]
extern crate serde_json;
extern crate wasm_bindgen;
extern crate wasm_bindgen_test;
use serde_json::Value;
use wasm_bindgen::*;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
fn pass() {
assert_eq!(1 + 1, 2);
fn json_str() -> &'static str {
r#"
{
"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
}
},
"expensive": 10
}
"#
}
fn target_json() -> Value {
json!([{
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
}])
}
#[wasm_bindgen_test]
fn select() {
let json: Value = jsonpath::select(JsValue::from_str(json_str()), "$..book[2]").into_serde().unwrap();
assert_eq!(json, target_json());
}
#[wasm_bindgen_test]
fn compile() {
let js_value = jsonpath::compile("$..book[2]");
assert_eq!(js_value.is_function(), true);
let cb: &js_sys::Function = JsCast::unchecked_ref(js_value.as_ref());
let cb_result: JsValue = cb.call1(&js_value, &JsValue::from_str(json_str())).unwrap();
let json: Value = cb_result.into_serde().unwrap();
assert_eq!(json, target_json());
}
#[wasm_bindgen_test]
fn selector() {
let js_value = jsonpath::selector(JsValue::from_str(json_str()));
assert_eq!(js_value.is_function(), true);
let cb: &js_sys::Function = JsCast::unchecked_ref(js_value.as_ref());
let cb_result: JsValue = cb.call1(&js_value, &JsValue::from_str("$..book[2]")).unwrap();
let json: Value = cb_result.into_serde().unwrap();
assert_eq!(json, target_json());
}
#[wasm_bindgen_test]
fn alloc_dealloc_json() {
let ptr = jsonpath::alloc_json(JsValue::from_str(json_str()));
assert_eq!(ptr > 0, true);
let json: Value = jsonpath::select(JsValue::from_f64(ptr as f64), "$..book[2]").into_serde().unwrap();
assert_eq!(json, target_json());
assert_eq!(jsonpath::dealloc_json(ptr), true);
let err = jsonpath::select(JsValue::from_f64(ptr as f64), "$..book[2]").as_string().unwrap();
assert_eq!(err, "Invalid pointer".to_string());
}
#[wasm_bindgen_test]
fn selector_struct() {
let mut selector = jsonpath::Selector::new();
selector.path("$..book[2]").unwrap();
selector.value(JsValue::from_str(json_str())).unwrap();
let json: Value = selector.select_to().unwrap().into_serde().unwrap();
assert_eq!(json, target_json());
}

View File

@ -1,9 +1,82 @@
<!DOCTYPE html>
<html>
<head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-3020058-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-3020058-1');
</script>
<meta charset="utf-8">
<meta property="og:image" content="https://avatars0.githubusercontent.com/u/1104423?s=400&amp;v=4"/>
<meta property="og:site_name" content="GitHub"/>
<meta property="og:type" content="object"/>
<meta property="og:title" content="freestrings/jsonpath"/>
<meta property="og:url" content="https://github.com/freestrings/jsonpath"/>
<meta property="og:description" content="JsonPath evaluator with Webassembly via Rust - freestrings/jsonpath"/>
<title>JsonPath evaluator - Webassembly via Rust</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<style>
/**
* GitHub Corners, page css
* Author: Tim Holman
*/
.code textarea {
border: 2px solid #eee;
outline: 0px;
height: 100%;
width: 100%;
font-family: monospace;
font-size: 10px;
}
.github-corner:hover .octo-arm {
animation: octocat-wave 560ms ease-in-out;
}
@keyframes octocat-wave {
0% {
transform: rotate(0deg);
}
20% {
transform: rotate(-25deg);
}
40% {
transform: rotate(10deg);
}
60% {
transform: rotate(-25deg);
}
80% {
transform: rotate(10deg);
}
100% {
transform: rotate(0deg);
}
}
@media (max-width: 500px) {
.github-corner:hover .octo-arm {
animation: none;
}
.github-corner .octo-arm {
animation: octocat-wave 560ms ease-in-out;
}
}
</style>
</head>
<body role="document">
<div class="container">
@ -15,7 +88,59 @@
</div>
-->
<div class="row">
<div class="col-md-6">
<div class="col-md-3">
<span class="badge badge-dark" style="margin-bottom: 15px">JsonPath</span> <span>(click to try)</span>
<table class="table">
<tbody>
<tr>
<td class="path"><a href="#/$.store.book[*].author">$.store.book[*].author</a></td>
</tr>
<tr>
<td class="path"><a href="#$..author">$..author</a></td>
</tr>
<tr>
<td class="path"><a href="#">$.store.*</a></td>
</tr>
<tr>
<td class="path"><a href="#">$.store..price</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[2]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[-2]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[0,1]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[:2]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[1:2]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[-2:]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[2:]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[?(@.isbn)]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$.store.book[?(@.price < 10)]</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..*</a></td>
</tr>
<tr>
<td class="path"><a href="#">$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]</a></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-4">
<span class="badge badge-dark" style="margin-bottom: 15px">Evaluator</span>
<div class="form-group">
<textarea id="json-example" class="form-control" style="min-width: 100%" rows="20"></textarea>
@ -29,12 +154,21 @@
</div>
</div>
</div>
<div class="col-md-6">
<div class="col-md-4">
<span class="badge badge-dark" style="margin-bottom: 15px">Result</span>
<pre class="prettyprint result" id="read-result" style="background-color: transparent; border: none;"></pre>
</div>
</div>
</div>
<a href="https://github.com/freestrings/jsonpath" class="github-corner" aria-label="View source on GitHub">
<svg width="80" height="80" viewBox="0 0 250 250" style="position: absolute; top: 0px; right: 0px; border: 0px;" aria-hidden="true">
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" fill="#151513"></path>
<path class="octo-arm" d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="#ffffff" style="transform-origin: 130px 106px;"></path>
<path class="octo-body"
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
fill="#ffffff"></path>
</svg>
</a>
<script src="./bootstrap.js"></script>
</body>
</html>

View File

@ -1,4 +1,4 @@
import * as jsonpath from "@browser/jsonpath-wasm";
import * as jsonpath from "jsonpath-wasm";
function getTextarea() {
return document.querySelector('#json-example');
@ -16,6 +16,10 @@ function getReadResult() {
return document.querySelector('#read-result');
}
function getLinks() {
return document.querySelectorAll('.path>a');
}
function initData(url) {
return fetch(url)
.then((res) => res.text())
@ -35,8 +39,12 @@ function initEvent() {
read();
}
getLinks().forEach(function(anchor) {
anchor.href = "#" + encodeURIComponent(anchor.textContent);
});
function read() {
let ret = jsonpath.read(getTextarea().value, getJsonpathInput().value);
let ret = jsonpath.select(getTextarea().value, getJsonpathInput().value);
if(typeof ret === 'string') {
getReadResult().innerText = ret;
} else {
@ -46,22 +54,26 @@ function initEvent() {
}
function readPathParam() {
let params = location.search.substr(1)
.split('&')
.map((item) => item.split('='))
.reduce((acc, param) => {
acc[param[0]] = decodeURIComponent(param[1]);
return acc;
}, {});
if(params.path) {
getJsonpathInput().value = params.path;
let doc = getReadBtn().ownerDocument;
let event = doc.createEvent('MouseEvents');
event.initEvent('click', true, true);
event.synthetic = true;
getReadBtn().dispatchEvent(event, true);
if(location.href.indexOf('#') > -1) {
readPath()
}
}
function forceClick(ctrl) {
let doc = ctrl.ownerDocument;
let event = doc.createEvent('MouseEvents');
event.initEvent('click', true, true);
event.synthetic = true;
ctrl.dispatchEvent(event, true);
}
function readPath() {
let query = location.href.substring(location.href.indexOf('#') + 1);
let path = decodeURIComponent(query);
getJsonpathInput().value = path;
forceClick(getReadBtn());
}
window.onpopstate = readPath;
initData('data/example.json').then(initEvent).then(readPathParam);

View File

@ -1,5 +1,5 @@
{
"name": "jsonpath-wasm",
"name": "jsonpath-wasm-evaluator",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,
@ -1010,13 +1010,14 @@
"dev": true
},
"copy-webpack-plugin": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.0.tgz",
"integrity": "sha512-iiDj+8nnZeW/i8vYJ3+ABSZkOefJnDYIGLojiZKKFDvf1wcEInABXH1+hN7axQMn04qvJxKjgVOee0e14XPtCg==",
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.2.tgz",
"integrity": "sha512-7nC7EynPrnBTtBwwbG1aTqrfNS1aTb9eEjSmQDqFtKAsJrR3uDb+pCDIFT2LzhW+SgGJxQcYzThrmXzzZ720uw==",
"dev": true,
"requires": {
"cacache": "^11.3.1",
"find-cache-dir": "^2.0.0",
"glob-parent": "^3.1.0",
"globby": "^7.1.1",
"is-glob": "^4.0.0",
"loader-utils": "^1.1.0",
@ -1928,9 +1929,9 @@
"dev": true
},
"fsevents": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz",
"integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==",
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz",
"integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==",
"dev": true,
"optional": true,
"requires": {
@ -1957,7 +1958,7 @@
"optional": true
},
"are-we-there-yet": {
"version": "1.1.4",
"version": "1.1.5",
"bundled": true,
"dev": true,
"optional": true,
@ -1983,7 +1984,7 @@
}
},
"chownr": {
"version": "1.0.1",
"version": "1.1.1",
"bundled": true,
"dev": true,
"optional": true
@ -2022,7 +2023,7 @@
}
},
"deep-extend": {
"version": "0.5.1",
"version": "0.6.0",
"bundled": true,
"dev": true,
"optional": true
@ -2071,7 +2072,7 @@
}
},
"glob": {
"version": "7.1.2",
"version": "7.1.3",
"bundled": true,
"dev": true,
"optional": true,
@ -2091,12 +2092,12 @@
"optional": true
},
"iconv-lite": {
"version": "0.4.21",
"version": "0.4.24",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safer-buffer": "^2.1.0"
"safer-buffer": ">= 2.1.2 < 3"
}
},
"ignore-walk": {
@ -2161,17 +2162,17 @@
"optional": true
},
"minipass": {
"version": "2.2.4",
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"minizlib": {
"version": "1.1.0",
"version": "1.2.1",
"bundled": true,
"dev": true,
"optional": true,
@ -2195,7 +2196,7 @@
"optional": true
},
"needle": {
"version": "2.2.0",
"version": "2.2.4",
"bundled": true,
"dev": true,
"optional": true,
@ -2206,18 +2207,18 @@
}
},
"node-pre-gyp": {
"version": "0.10.0",
"version": "0.10.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"detect-libc": "^1.0.2",
"mkdirp": "^0.5.1",
"needle": "^2.2.0",
"needle": "^2.2.1",
"nopt": "^4.0.1",
"npm-packlist": "^1.1.6",
"npmlog": "^4.0.2",
"rc": "^1.1.7",
"rc": "^1.2.7",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4"
@ -2234,13 +2235,13 @@
}
},
"npm-bundled": {
"version": "1.0.3",
"version": "1.0.5",
"bundled": true,
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.1.10",
"version": "1.2.0",
"bundled": true,
"dev": true,
"optional": true,
@ -2317,12 +2318,12 @@
"optional": true
},
"rc": {
"version": "1.2.7",
"version": "1.2.8",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"deep-extend": "^0.5.1",
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
@ -2352,16 +2353,16 @@
}
},
"rimraf": {
"version": "2.6.2",
"version": "2.6.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"glob": "^7.0.5"
"glob": "^7.1.3"
}
},
"safe-buffer": {
"version": "5.1.1",
"version": "5.1.2",
"bundled": true,
"dev": true,
"optional": true
@ -2379,7 +2380,7 @@
"optional": true
},
"semver": {
"version": "5.5.0",
"version": "5.6.0",
"bundled": true,
"dev": true,
"optional": true
@ -2432,17 +2433,17 @@
"optional": true
},
"tar": {
"version": "4.4.1",
"version": "4.4.8",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"chownr": "^1.0.1",
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.2.4",
"minizlib": "^1.1.0",
"minipass": "^2.3.4",
"minizlib": "^1.1.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.1",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.2"
}
},
@ -2453,12 +2454,12 @@
"optional": true
},
"wide-align": {
"version": "1.1.2",
"version": "1.1.3",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"string-width": "^1.0.2"
"string-width": "^1.0.2 || 2"
}
},
"wrappy": {
@ -2468,7 +2469,7 @@
"optional": true
},
"yallist": {
"version": "3.0.2",
"version": "3.0.3",
"bundled": true,
"dev": true,
"optional": true
@ -2655,9 +2656,9 @@
}
},
"homedir-polyfill": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz",
"integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
"integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
"dev": true,
"requires": {
"parse-passwd": "^1.0.0"
@ -3467,9 +3468,9 @@
"dev": true
},
"nan": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
"version": "2.13.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz",
"integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==",
"dev": true,
"optional": true
},
@ -4779,9 +4780,9 @@
"dev": true
},
"supports-color": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
@ -5200,9 +5201,9 @@
}
},
"webpack-cli": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.2.3.tgz",
"integrity": "sha512-Ik3SjV6uJtWIAN5jp5ZuBMWEAaP5E4V78XJ2nI+paFPh8v4HPSwo/myN0r29Xc/6ZKnd2IdrAlpSgNOu2CDQ6Q==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.0.tgz",
"integrity": "sha512-t1M7G4z5FhHKJ92WRKwZ1rtvi7rHc0NZoZRbSkol0YKl4HvcC8+DsmGDmK7MmZxHSAetHagiOsjOB6MmzC2TUw==",
"dev": true,
"requires": {
"chalk": "^2.4.1",
@ -5215,13 +5216,13 @@
"loader-utils": "^1.1.0",
"supports-color": "^5.5.0",
"v8-compile-cache": "^2.0.2",
"yargs": "^12.0.4"
"yargs": "^12.0.5"
},
"dependencies": {
"camelcase": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
"integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true
},
"decamelize": {
@ -5230,58 +5231,6 @@
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true,
"requires": {
"locate-path": "^3.0.0"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true,
"requires": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
}
},
"p-limit": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz",
"integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true,
"requires": {
"p-limit": "^2.0.0"
}
},
"p-try": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz",
"integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==",
"dev": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
},
"yargs": {
"version": "12.0.5",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",

View File

@ -1,32 +1,15 @@
{
"name": "jsonpath-wasm",
"name": "jsonpath-wasm-evaluator",
"version": "0.1.0",
"main": "index.js",
"scripts": {
"build": "webpack --config webpack.config.js",
"start": "webpack-dev-server"
},
"repository": {
"type": "git",
"url": "git+https://github.com/freestrings/jsonpath.git"
},
"keywords": [
"webassembly",
"wasm",
"rust",
"webpack",
"jsonpath"
],
"author": "Changseok Han <freestrings@gmail.com>",
"license": "(MIT OR Apache-2.0)",
"bugs": {
"url": "https://github.com/freestrings/jsonpath/issues"
},
"homepage": "https://github.com/freestrings/jsonpath#readme",
"devDependencies": {
"copy-webpack-plugin": "^5.0.0",
"copy-webpack-plugin": "^5.0.1",
"webpack": "^4.29.6",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.5"
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
}
}

View File

@ -1,4 +1,4 @@
import * as jpw from "@browser/jsonpath-wasm";
import * as jpw from "jsonpath-wasm";
import * as jp from "jsonpath/jsonpath.js";
function run(message, iter, cb) {
@ -61,7 +61,7 @@ let path = '$..book[?(@.price<30 && @.category=="fiction")]';
let template = jpw.compile(path);
let selector = jpw.selector(json);
let ptr = jpw.alloc_json(json);
let ptr = jpw.allocJson(json);
if(ptr == 0) console.error('invalid ptr');
let iterCount = 2000;
@ -83,7 +83,7 @@ run('jsonpath', iterCount, function() { jp.query(json, path) })
return run('jsonpath-wasm- select-alloc', iterCount, function() { jpw.select(ptr, path) });
})
.finally(function() {
if(!jpw.dealloc_json(ptr)) {
if(!jpw.deallocJson(ptr)) {
console.error('fail to dealloc');
}
});

View File

@ -1,5 +1,5 @@
{
"name": "jsonpath-wasm",
"name": "jsonpath-wasm-bench",
"version": "0.1.0",
"lockfileVersion": 1,
"requires": true,

View File

@ -1,28 +1,11 @@
{
"name": "jsonpath-wasm",
"name": "jsonpath-wasm-bench",
"version": "0.1.0",
"main": "index.js",
"scripts": {
"build": "webpack --config webpack.config.js",
"start": "webpack-dev-server"
},
"repository": {
"type": "git",
"url": "git+https://github.com/freestrings/jsonpath.git"
},
"keywords": [
"webassembly",
"wasm",
"rust",
"webpack",
"jsonpath"
],
"author": "Changseok Han <freestrings@gmail.com>",
"license": "(MIT OR Apache-2.0)",
"bugs": {
"url": "https://github.com/freestrings/jsonpath/issues"
},
"homepage": "https://github.com/freestrings/jsonpath#readme",
"devDependencies": {
"copy-webpack-plugin": "^5.0.0",
"webpack": "^4.29.6",