99 Commits

Author SHA1 Message Date
25cffed2d7 Remove jsonpath-rs build in travis.yml 2020-02-15 01:15:24 +09:00
bab2ff38f7 Move javascript examples directory under wasm 2020-02-15 00:56:07 +09:00
ffd87cfbe4 Not support 'jsonpath-rs' since 0.2.4 2020-02-15 00:46:00 +09:00
7597325f59 Bump up 0.24 - jsonpath-rs, jsonpath-wasm 2020-02-14 21:48:00 +09:00
2ba3930a8c Bump up 0.24 - WebAssembly 2020-02-14 21:11:31 +09:00
844a96b2d1 Bump up 0.24 2020-02-14 21:08:27 +09:00
3b4d2b4ffc fix clippy error 2020-02-10 23:53:56 +09:00
c2a6f3b319 close #33 2020-02-10 23:34:55 +09:00
8e10128826 fix clippy error 2020-02-10 23:26:20 +09:00
ad39c9e668 Invalid result on second attribute check #33 2020-02-10 23:26:20 +09:00
636618e4ac fix #29 check for overflow 2020-02-10 23:24:56 +09:00
9fa0f74ce9 Fix clippy warnings 2020-01-07 00:08:04 +09:00
cc5ce6f65f Bump up env-logger from 0.6 to 0.7 2020-01-07 00:07:00 +09:00
1152af6c68 Bump handlebars from 4.1.2 to 4.5.3 in /examples/nodejs-rs
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-06 23:40:35 +09:00
1a54a36cd3 Bump handlebars from 4.1.2 to 4.5.3 in /nodejs
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-06 23:39:18 +09:00
5b878d7ba7 add lua + openresty example 2019-10-28 22:42:02 +09:00
d84d0d845c fix clippy error 2019-10-28 22:12:52 +09:00
c3ac7e40e8 코드 정리 2019-09-22 22:10:25 +09:00
c8ab8ad107 proxy_pass 디렉티브 테스트 2019-09-22 16:49:44 +09:00
8c24411c3f content_by_lua_file directive 테스트 추가 2019-09-22 16:49:44 +09:00
422a23ee57 openresty 테스트 2019-09-22 16:49:44 +09:00
b5c5d6b88e lua 프로젝트 레이아웃 변경 2019-09-22 16:49:41 +09:00
ea7599c012 first commit lua ffi 2019-09-22 16:47:17 +09:00
9276c0aa02 필터에 중첩된 상대경로 잘못찾는 문제 수정 2019-09-19 23:30:31 +09:00
2b875c8a7e Bump all npm dependencies 2019-09-01 14:42:56 +09:00
6a89553c33 Replace fun input with ownership #22 2019-08-29 23:10:14 +09:00
fe376c4483 fix build 2019-08-29 23:09:07 +09:00
5a52ded4ca add test from remove() 2019-08-29 23:09:07 +09:00
773ea3a3b3 fix test 2019-08-29 23:09:07 +09:00
17a8608392 Return Option<Value> from fun on replace_with to all user to return None (remove the value and not replace with Null) 2019-08-29 23:09:07 +09:00
e0db04aed9 Rollback #22 - build failed on travis-ci 2019-08-29 23:09:07 +09:00
d5364ad74a Close #24 - workspace configuration 2019-08-29 23:09:07 +09:00
67991df1f2 improve performance avoid remove & insert to map 2019-08-29 23:09:07 +09:00
15e6c6065b pass value not reference to fun 2019-08-29 23:09:07 +09:00
fab07adc5a improve performance avoid remove & insert to map 2019-08-29 23:09:00 +09:00
4b62fcd376 pass value not reference to fun 2019-08-29 23:08:58 +09:00
2daef2c938 Rollback #22 - build failed on travis-ci 2019-08-15 22:57:36 +09:00
43d092cb35 Close #24 - workspace configuration 2019-08-15 22:26:52 +09:00
19f0878b5a Replace fun input with ownership #22 2019-08-15 21:56:30 +09:00
b2e27b423a fix wasm build 2019-08-15 21:20:52 +09:00
88e6320cf7 improve performance avoid remove & insert to map 2019-08-15 21:20:52 +09:00
8b85ec9d61 pass value not reference to fun 2019-08-15 21:20:52 +09:00
f5e46882da Merge branch 'gkorland-test_delete' 2019-08-14 09:58:46 +09:00
53c4711d1a add test for delete 2019-08-11 11:18:07 +03:00
31612315b8 move lifetime to result #19 2019-08-05 10:44:36 +09:00
2efb019155 Update lib.rs 2019-07-31 16:34:24 +03:00
d9b9e9d8bd move lifetime to result
lifetime should be on the Vec<&'a Value> and not on the input
2019-07-31 16:22:35 +03:00
c0a5296451 Merge branch 'dependentbot/npm_and_yarn' 2019-07-14 23:19:44 +09:00
6c983ced99 Bump lodash from 4.17.11 to 4.17.14 in /wasm/www_bench
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 23:18:36 +09:00
d0f93bde49 Bump lodash from 4.17.11 to 4.17.14 in /wasm/www
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 23:17:57 +09:00
d7423e35da Bump lodash from 4.17.11 to 4.17.14 in /wasm/tests
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 23:17:29 +09:00
a23ab7a519 Bump lodash from 4.17.11 to 4.17.14 in /nodejs
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 23:17:03 +09:00
d4140c8ed5 Bump lodash from 4.17.11 to 4.17.14 in /examples/nodejs-rs
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 23:16:11 +09:00
595a2d8528 Bump lodash from 4.17.11 to 4.17.14 in /examples/browser
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 23:15:39 +09:00
e8e9dbfe1c Merge pull request #11 from measlytwerp/patch-1
Added `query` to the keywords
2019-07-14 23:09:53 +09:00
b644c5b0a6 Dropped javascript keyword in favour of query 2019-07-13 16:35:49 +09:30
5c29b54e3a Added query to the keywords
I added `query` to the keywords to help people find this on crates.io as there are a few similar crates that use `json` and `query`.
2019-07-11 22:34:42 +09:30
dde0d5dc2e test coverage 개선 2019-06-26 18:19:52 +09:00
a553b4b06b wasm build 추가 2019-06-26 17:53:19 +09:00
3d33e8bd08 빌드패스에서 'benchs' 제거 2019-06-26 17:01:43 +09:00
8f01598e05 code coverage 90% 2019-06-26 15:07:49 +09:00
cab5177811 the clippy lints 2019-06-25 23:56:13 +09:00
9a28faf058 apply clippy lints - wasm, nodejs 2019-06-25 23:41:10 +09:00
319186b1d9 apply clippy lints - tests 2019-06-25 22:57:21 +09:00
2f0d29d644 parser change to private module 2019-06-25 22:07:59 +09:00
b910ed35f9 apply clippy lints 2019-06-25 22:01:31 +09:00
f5717d6d26 remove useless function 2019-06-25 13:21:13 +09:00
f1fda2af13 publish 0.2.3 - fixed #7 2019-06-24 14:37:58 +09:00
6ad4432737 jsonpath-rs 0.2.3 2019-06-24 14:35:14 +09:00
13816df970 jsonpath-wasm 0.2.3 2019-06-24 14:35:14 +09:00
030dccc8cc jsonpath_lib 0.2.3 2019-06-24 14:20:29 +09:00
28ad9c903f remove indexmap crate 2019-06-24 14:12:00 +09:00
be29571670 fix broken build in osx. remove neon-serde 2019-06-24 13:25:54 +09:00
59dad2ea02 update example 2019-06-23 23:59:18 +09:00
967df1b787 Invalid wildcard filter results #7 - nodejs, wasm 2019-06-23 18:56:30 +09:00
6d38c67e90 Invalid wildcard filter results #7 2019-06-23 18:27:25 +09:00
053be432f2 fix wildcard filter 2019-06-23 18:25:46 +09:00
d384079842 Leaves 처리 위치 변경 2019-06-23 17:22:58 +09:00
5f832e8fe7 code coverage 적용 2019-06-20 22:33:21 +09:00
4390feb807 add tarpaulin setting 2019-06-20 22:31:33 +09:00
f536391b71 select code coverage 2019-06-20 22:31:33 +09:00
c19c75dac5 parser code coverage 2019-06-20 22:31:33 +09:00
ad47444b7a src/lib.rs code coverage 2019-06-20 22:30:26 +09:00
488e0b400f jsonpath-rs unit test for 0.2.2 2019-06-19 16:17:58 +09:00
fff0e869cb improve error message 2019-06-19 15:10:50 +09:00
6a270c9456 IntelliJ rustfmt default rule 적용 2019-06-19 11:52:53 +09:00
ebd49c2205 Resolved #6 (from v0.2.2), new array filter (range step, escaped quote notation, array keys) 2019-06-19 11:45:55 +09:00
2537469f03 0.2.2 docs 2019-06-18 14:19:08 +09:00
2e0f78f017 0.2.2 배포 전까지 jsonpath-rs unit test 임시 롤백 2019-06-18 13:38:11 +09:00
5d36a0cf15 array keys - js unit test 2019-06-18 13:27:28 +09:00
a72a13117e array range with step - js unit test 2019-06-18 13:27:09 +09:00
964e0c00f5 escaped quote notation - js unit test 2019-06-18 13:26:42 +09:00
de97e2f95a array keys 2019-06-18 13:26:36 +09:00
74666d264e array range with step 2019-06-18 13:26:36 +09:00
51deec66d0 escaped quote notation 2019-06-18 13:26:36 +09:00
909c851dcc Results do not match other implementations - js unit test 2019-06-18 13:25:59 +09:00
b41b9f3aa6 Results do not match other implementations #6 2019-06-17 12:07:52 +09:00
1a5e8cc025 IntelliJ Run 설정 수정 2019-06-17 11:27:12 +09:00
5abbfba254 테스트 코드에 select 대신 select_as를 사용하게 수정 2019-06-17 11:19:25 +09:00
96 changed files with 9139 additions and 6607 deletions

View File

@ -4,9 +4,12 @@
<option name="command" value="test --package jsonpath_lib" />
<option name="allFeatures" value="false" />
<option name="nocapture" value="true" />
<option name="backtrace" value="SHORT" />
<option name="emulateTerminal" value="false" />
<option name="backtrace" value="NO" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<envs />
<method v="2" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>

View File

@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="selector" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<configuration default="false" name="mutable" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="channel" value="DEFAULT" />
<option name="command" value="test --package jsonpath_lib --test selector &quot;&quot;" />
<option name="command" value="test --package jsonpath_lib --test mutable &quot;&quot;" />
<option name="allFeatures" value="false" />
<option name="nocapture" value="false" />
<option name="backtrace" value="SHORT" />

View File

@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="parser" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="channel" value="DEFAULT" />
<option name="command" value="test --package jsonpath_lib --test parser &quot;&quot;" />
<option name="command" value="test --package jsonpath_lib --lib parser::parser_tests" />
<option name="allFeatures" value="false" />
<option name="nocapture" value="false" />
<option name="backtrace" value="SHORT" />

View File

@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="serde" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<configuration default="false" name="readme" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="channel" value="DEFAULT" />
<option name="command" value="test --package jsonpath_lib --test serde &quot;&quot;" />
<option name="command" value="test --package jsonpath_lib --test readme &quot;&quot;" />
<option name="allFeatures" value="false" />
<option name="nocapture" value="false" />
<option name="backtrace" value="SHORT" />

View File

@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="tokenizer" type="CargoCommandRunConfiguration" factoryName="Cargo Command">
<option name="channel" value="DEFAULT" />
<option name="command" value="test --package jsonpath_lib --test tokenizer &quot;&quot;" />
<option name="command" value="test --package jsonpath_lib --lib parser::tokenizer_tests" />
<option name="allFeatures" value="false" />
<option name="nocapture" value="false" />
<option name="backtrace" value="SHORT" />

View File

@ -1,5 +1,9 @@
language: rust
sudo: false
sudo: required
addons:
apt:
packages:
- libssl-dev
cache: cargo
@ -13,27 +17,28 @@ matrix:
- rust: stable
os: linux
env: RUST_BACKTRACE=1
addons:
chrome: stable
before_cache: |
if [[ "$TRAVIS_RUST_VERSION" == stable ]]; then
cargo install cargo-tarpaulin -f
fi
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)
- cargo install-update -a
- curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
- rustup component add clippy
script:
- cargo clean
- cargo clippy -- -D warnings
- cargo build --verbose --all
- cargo clippy --all-targets --all-features -- -D warnings -A clippy::cognitive_complexity
- cargo test --verbose --all
- cd wasm && cargo clippy -- -D warnings -A clippy::suspicious_else_formatting
- cd ../../
after_success: |
cargo tarpaulin --exclude-files nodejs wasm parser/mod.rs --out Xml
bash <(curl -s https://codecov.io/bash)
- 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)
- cargo install-update -a
- curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
script:
- cargo clean
- cargo build --verbose --all
- cargo test --verbose --all
- language: node_js
@ -48,13 +53,12 @@ matrix:
- sh /tmp/rustup.sh -y
- export PATH="$HOME/.cargo/bin:$PATH"
- source "$HOME/.cargo/env"
- npm install -g neon-cli
- cd nodejs
- node -v
- npm -v
- npm install
before_script:
- curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
script:
- npm test
- bash ./build-wasm.sh
- language: node_js
os: osx
node_js:
@ -67,10 +71,9 @@ matrix:
- sh /tmp/rustup.sh -y
- export PATH="$HOME/.cargo/bin:$PATH"
- source "$HOME/.cargo/env"
- npm install -g neon-cli
- cd nodejs
- node -v
- npm -v
- npm install
before_script:
- curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
script:
- npm test
- bash ./build-wasm.sh

View File

@ -1,15 +1,15 @@
[package]
name = "jsonpath_lib"
version = "0.2.0"
version = "0.2.4"
authors = ["Changseok Han <freestrings@gmail.com>"]
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"
description = "It is JsonPath engine written in Rust. it provide a similar API interface in Webassembly and Javascript too. - Webassembly Demo: https://freestrings.github.io/jsonpath"
readme = "README.md"
keywords = ["jsonpath", "json", "webassembly", "nodejs", "javascript"]
keywords = ["jsonpath", "json", "webassembly", "nodejs", "query"]
repository = "https://github.com/freestrings/jsonpath"
documentation = "https://docs.rs/jsonpath_lib/0.1.0/jsonpath_lib"
documentation = "https://docs.rs/jsonpath_lib/0.2.4/jsonpath_lib"
license = "MIT"
categories = ["parsing"]
@ -19,19 +19,16 @@ travis-ci = { repository = "freestrings/jsonpath", branch = "master" }
[dependencies]
log = "0.4"
env_logger = "0.6.0"
env_logger = "0.7"
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
indexmap = "1.0.2"
array_tool = "~1.0.3"
[dev-dependencies]
bencher = "0.1.5"
array_tool = "1.0.3"
[lib]
name = "jsonpath_lib"
path = "src/lib.rs"
crate-type = ["cdylib", "rlib"]
[profile.release]
#debug = true
#lto = false
#lto = false

View File

@ -2,16 +2,15 @@
[![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)
![npm](https://img.shields.io/npm/v/jsonpath-rs.svg?label=npm%20%60jsonpath-rs%60)
![npm](https://img.shields.io/npm/v/jsonpath-wasm.svg?label=npm%20%60jsonpath-wasm%60)
![Codecov](https://img.shields.io/codecov/c/github/freestrings/jsonpath.svg?token=92c41b4e7cf04a9cbebc08f68c5da615)
`Rust` 버전 [JsonPath](https://goessner.net/articles/JsonPath/) 구현이다. `Webassembly``Javascript`에서도 유사한 API 인터페이스를 제공 한다.
It is JsonPath [JsonPath](https://goessner.net/articles/JsonPath/) engine written in `Rust`. it provide a similar 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` too.
- [Webassembly Demo](https://freestrings.github.io/jsonpath/)
- [NPM jsonpath-wasm - webassembly](https://www.npmjs.com/package/jsonpath-wasm)
- [NPM jsonpath-rs - native addon](https://www.npmjs.com/package/jsonpath-rs)
## Rust API
@ -91,7 +90,7 @@ let result = selector_mut
0
};
json!(age)
Some(json!(age))
}).unwrap()
.take().unwrap();
@ -352,7 +351,7 @@ let ret = jsonpath::replace_with(json_obj, "$..[?(@.age == 20)].age", &mut |v| {
0
};
json!(age)
Some(json!(age))
}).unwrap();
assert_eq!(ret, json!({
@ -387,18 +386,6 @@ import * as jsonpath from "jsonpath-wasm";
const jsonpath = require('jsonpath-wasm');
```
##### jsonpath-rs (NodeJS only)
Goto [`jsonpath-rs` npmjs.org](https://www.npmjs.com/package/jsonpath-rs)
```javascript
const jsonpath = require('jsonpath-rs');
```
</details>
<details><summary><b>Javascript - jsonpath.Selector class</b></summary>
##### jsonpath-wasm
`wasm-bindgen` 리턴 타입 제약 때문에 빌더 패턴은 지원하지 않는다.
@ -434,42 +421,6 @@ console.log(JSON.stringify(ret) == JSON.stringify(retObj));
// => 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 retObj = selector.select();
console.log(JSON.stringify(ret) == JSON.stringify(retObj));
// => true
```
</details>
<details><summary><b>Javascript - jsonpath.SelectorMut class</b></summary>
빌더 패턴 제약은 `Selector class`와 동일하다.
```javascript

9
bench.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/bash
set -e
#
# rustup default nightly
#
cargo bench --manifest-path ./benchmark/Cargo.toml

View File

@ -1,44 +0,0 @@
#!/bin/bash
set -e
DIR="$(pwd)"
cd "${DIR}"/bench_bin && cargo build --release
ITER=100000
printf "\n\n$..book[?(@.price<30 && @.category=="fiction")] (loop ${ITER})"
printf "\n\n"
__default () {
echo "Rust - select: " && time ./bench.sh select ${ITER}
printf "\n"
sleep 1
cd "${DIR}"/javascript && echo "NodeJs - jsonpath - query: " && time ./bench.sh jsonpath ${ITER}
printf "\n"
sleep 1
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-rs - select:" && time ./bench.sh nativeSelect ${ITER}
}
__extra () {
echo "Rust - selector: " && time ./bench.sh selector ${ITER}
printf "\n"
sleep 1
echo "Rust - compile: " && time ./bench.sh compile ${ITER}
printf "\n"
sleep 1
cd "${DIR}"/javascript && echo "NodeJs - jsonpath - query: " && time ./bench.sh jsonpath ${ITER}
printf "\n"
sleep 1
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-rs - selector: " && time ./bench.sh nativeSelector ${ITER}
printf "\n"
sleep 1
cd "${DIR}"/javascript && echo "NodeJs - jsonpath-rs - compile: " && time ./bench.sh nativeCompile ${ITER}
printf "\n"
}
if [ "$1" = "extra" ]; then
__extra
else
__default
fi

View File

@ -1,3 +0,0 @@
{
"lockfileVersion": 1
}

4
benchmark/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.idea/*
.vscode
/target/
Cargo.lock

17
benchmark/Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "jsonpath_lib_benches"
version = "0.1.0"
authors = ["Changseok Han <freestrings@gmail.com>"]
description = "jsonpath_lib benchmark"
license = "MIT"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
jsonpath_lib = { path = "../" }
[dev-dependencies]
bencher = "0.1.5"
[[bin]]
name = "jsonpath_lib_benches"
path = "src/main.rs"

View File

@ -22,7 +22,7 @@ fn read_json(path: &str) -> String {
}
fn get_string() -> String {
read_json("./benches/example.json")
read_json("./example.json")
}
fn get_json() -> Value {
@ -109,7 +109,7 @@ fn bench_select_as(b: &mut Bencher) {
#[bench]
fn bench_delete(b: &mut Bencher) {
let json = get_json();
let mut selector = SelectorMut::new();
let mut selector = SelectorMut::default();
let _ = selector.str_path(get_path());
b.iter(move || {
@ -123,13 +123,13 @@ fn bench_delete(b: &mut Bencher) {
fn bench_select_to_compare_with_delete(b: &mut Bencher) {
let json = &get_json();
let mut selector = Selector::new();
let mut selector = Selector::default();
let _ = selector.str_path(get_path());
b.iter(move || {
for _ in 1..100 {
let json = json.clone();
let mut s = Selector::new();
let mut s = Selector::default();
let _ = s.compiled_path(selector.node_ref().unwrap()).value(&json);
let _ = s.select();
}

View File

@ -19,7 +19,7 @@ fn read_json(path: &str) -> String {
}
fn get_string() -> String {
read_json("./benches/example.json")
read_json("./example.json")
}
fn get_json() -> Value {
@ -53,7 +53,7 @@ fn _selector(b: &mut Bencher, index: usize) {
let json = get_json();
b.iter(move || {
for _ in 1..100 {
let mut selector = jsonpath::Selector::new();
let mut selector = jsonpath::Selector::default();
let _ = selector.str_path(get_path(index));
selector.value(&json);
let r = selector.select();

4501
benchmark/big_example.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -34,4 +34,4 @@
}
},
"expensive": 10
}
}

View File

@ -43,7 +43,6 @@ function getJson() {
const path = '$..book[?(@.price<30 && @.category=="fiction")]';
const jp = require('jsonpath');
const jpw = require('jsonpath-wasm');
const jpwRs = require('jsonpath-rs');
function jsonpath() {
for (var i = 0; i < iter; i++) {
@ -51,26 +50,6 @@ function jsonpath() {
}
}
function nativeCompile() {
let template = jpwRs.compile(path);
for (var i = 0; i < iter; i++) {
let _ = template(JSON.stringify(json));
}
}
function nativeSelector() {
let selector = jpwRs.selector(getJson());
for (var i = 0; i < iter; i++) {
let _ = selector(path);
}
}
function nativeSelect() {
for (var i = 0; i < iter; i++) {
let _ = jpwRs.select(JSON.stringify(json), path);
}
}
function wasmSelector() {
let selector = jpw.selector(getJson());
for (var i = 0; i < iter; i++) {

1
benchmark/src/main.rs Normal file
View File

@ -0,0 +1 @@
fn main() {}

View File

@ -11,7 +11,7 @@ WASM_BROWSER_PKG="${WASM}"/browser_pkg
WASM_NODEJS_PKG="${WASM}"/nodejs_pkg
WASM_ALL_PKG="${WASM}"/all_pkg
WASM_TEST="${WASM}"/tests
BENCHES="${DIR}"/benches
BENCHES="${DIR}"/benchmark
BENCHES_JS="${BENCHES}"/javascript
NODEJS="${DIR}"/nodejs
DOCS="${DIR}"/docs
@ -28,6 +28,16 @@ __cargo_clean () {
cd "${DIR}" && cargo clean
}
if [ "$1" = "clippy" ]
then
echo
__msg "clippy"
cargo clippy -- -D warnings && \
cargo clippy --all-targets --all-features -- -D warnings -A clippy::cognitive_complexity && \
cd "${WASM}" && cargo clippy -- -A clippy::suspicious_else_formatting && \
cd "${NODEJS}" && cargo clippy
fi
echo
__msg "clean"
rm -rf \
@ -96,8 +106,7 @@ cd "${WASM_WWW_BENCH}" && \
npm link jsonpath-wasm
cd "${BENCHES_JS}" && \
npm link jsonpath-wasm && \
npm link jsonpath-rs
npm link jsonpath-wasm
cd "${WASM_TEST}" && \
npm link jsonpath-wasm

9
coverage.sh Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
#
# cargo install cargo-tarpaulin
#
set -e
cargo tarpaulin --exclude-files nodejs wasm parser/mod.rs -v --all

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -55,24 +55,24 @@
/******/ "../all_pkg/jsonpath_wasm_bg.wasm": function() {
/******/ return {
/******/ "./jsonpath_wasm": {
/******/ "__wbindgen_cb_forget": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
/******/ },
/******/ "__wbg_error_af8a3e3880eae1c8": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_error_af8a3e3880eae1c8"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ },
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
/******/ },
/******/ "__wbg_error_bb0b0e541b3bff31": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_error_bb0b0e541b3bff31"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ },
/******/ "__wbindgen_cb_forget": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
/******/ },
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ },
/******/ "__wbg_call_88d2a6153573084e": function(p0i32,p1i32,p2i32,p3i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_call_88d2a6153573084e"](p0i32,p1i32,p2i32,p3i32);
/******/ },
@ -94,11 +94,11 @@
/******/ "__wbindgen_rethrow": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_rethrow"](p0i32);
/******/ },
/******/ "__wbindgen_closure_wrapper22": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper22"](p0i32,p1i32,p2i32);
/******/ "__wbindgen_closure_wrapper115": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper115"](p0i32,p1i32,p2i32);
/******/ },
/******/ "__wbindgen_closure_wrapper24": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper24"](p0i32,p1i32,p2i32);
/******/ "__wbindgen_closure_wrapper117": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper117"](p0i32,p1i32,p2i32);
/******/ }
/******/ }
/******/ };
@ -198,7 +198,7 @@
/******/ promises.push(installedWasmModuleData);
/******/ else {
/******/ var importObject = wasmImportObjects[wasmModuleId]();
/******/ var req = fetch(__webpack_require__.p + "" + {"../all_pkg/jsonpath_wasm_bg.wasm":"7a2fe8020c3403dd4ce6"}[wasmModuleId] + ".module.wasm");
/******/ var req = fetch(__webpack_require__.p + "" + {"../all_pkg/jsonpath_wasm_bg.wasm":"33fd09cf53124f20b1e8"}[wasmModuleId] + ".module.wasm");
/******/ var promise;
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {

34
docs/bootstrap.js vendored
View File

@ -55,24 +55,24 @@
/******/ "../all_pkg/jsonpath_wasm_bg.wasm": function() {
/******/ return {
/******/ "./jsonpath_wasm": {
/******/ "__wbindgen_cb_forget": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
/******/ },
/******/ "__wbg_error_af8a3e3880eae1c8": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_error_af8a3e3880eae1c8"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ },
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_json_parse": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_parse"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_json_serialize": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_json_serialize"](p0i32,p1i32);
/******/ },
/******/ "__wbg_error_bb0b0e541b3bff31": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_error_bb0b0e541b3bff31"](p0i32,p1i32);
/******/ },
/******/ "__wbindgen_object_drop_ref": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_object_drop_ref"](p0i32);
/******/ },
/******/ "__wbindgen_cb_forget": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_cb_forget"](p0i32);
/******/ },
/******/ "__wbindgen_string_new": function(p0i32,p1i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_string_new"](p0i32,p1i32);
/******/ },
/******/ "__wbg_call_88d2a6153573084e": function(p0i32,p1i32,p2i32,p3i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbg_call_88d2a6153573084e"](p0i32,p1i32,p2i32,p3i32);
/******/ },
@ -94,11 +94,11 @@
/******/ "__wbindgen_rethrow": function(p0i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_rethrow"](p0i32);
/******/ },
/******/ "__wbindgen_closure_wrapper22": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper22"](p0i32,p1i32,p2i32);
/******/ "__wbindgen_closure_wrapper115": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper115"](p0i32,p1i32,p2i32);
/******/ },
/******/ "__wbindgen_closure_wrapper24": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper24"](p0i32,p1i32,p2i32);
/******/ "__wbindgen_closure_wrapper117": function(p0i32,p1i32,p2i32) {
/******/ return installedModules["../all_pkg/jsonpath_wasm.js"].exports["__wbindgen_closure_wrapper117"](p0i32,p1i32,p2i32);
/******/ }
/******/ }
/******/ };
@ -198,7 +198,7 @@
/******/ promises.push(installedWasmModuleData);
/******/ else {
/******/ var importObject = wasmImportObjects[wasmModuleId]();
/******/ var req = fetch(__webpack_require__.p + "" + {"../all_pkg/jsonpath_wasm_bg.wasm":"7a2fe8020c3403dd4ce6"}[wasmModuleId] + ".module.wasm");
/******/ var req = fetch(__webpack_require__.p + "" + {"../all_pkg/jsonpath_wasm_bg.wasm":"33fd09cf53124f20b1e8"}[wasmModuleId] + ".module.wasm");
/******/ var promise;
/******/ if(importObject instanceof Promise && typeof WebAssembly.compileStreaming === 'function') {
/******/ promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {

View File

@ -1,31 +0,0 @@
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
);

View File

@ -1,658 +0,0 @@
{
"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.2",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
"integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
"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

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

View File

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

5
lua/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.idea/*
.vscode
/target/
Cargo.lock
docker_example/ab_results/**

14
lua/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "jsonpath_lua"
version = "0.1.0"
authors = ["Changseok Han <freestrings@gmail.com>"]
license = "MIT"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] }
jsonpath_lib = { path = "../" }
[[bin]]
name = "bench"
path = "bench_lua_vs_rust/example.rs"

View File

@ -0,0 +1,22 @@
local jsonpath = require("jsonpath")
local iter;
if arg[1] == nil or arg[1] == '' then
iter = 5000;
else
iter = tonumber(arg[1]);
end
print(string.format("%s - %u", "lua iter", iter));
local file = io.open("../../benchmark/example.json", "r");
io.input(file)
local data = io.read("*a");
io.close(file);
jsonpath.init('../target/release/deps/libjsonpath_lib.so')
local template = jsonpath.compile("$..book[?(@.price<30 && @.category==\"fiction\")]");
for i = 0, iter do
local r = template(data);
-- print(r);
end

View File

@ -0,0 +1,46 @@
extern crate jsonpath_lib as jsonpath;
extern crate serde;
extern crate serde_json;
use std::io::Read;
use serde_json::Value;
fn read_json(path: &str) -> String {
let mut f = std::fs::File::open(path).unwrap();
let mut contents = String::new();
f.read_to_string(&mut contents).unwrap();
contents
}
fn get_string() -> String {
read_json("../../benchmark/example.json")
}
fn get_json() -> Value {
let string = get_string();
serde_json::from_str(string.as_str()).unwrap()
}
fn get_path() -> &'static str {
r#"$..book[?(@.price<30 && @.category=="fiction")]"#
}
fn main() {
let args: Vec<String> = std::env::args().collect();
let iter = if args.len() < 2 { 5000_usize } else { args[1].as_str().parse::<usize>().unwrap() };
println!("rust iter - {}", iter);
let json = get_json();
for _ in 0..iter {
let mut selector = jsonpath::Selector::default();
let _ = selector.str_path(get_path());
selector.value(&json);
let r = selector.select();
if r.is_err() {
panic!();
}
// println!("{:?}", serde_json::to_string(&r.expect("")).unwrap());
}
}

27
lua/bench_lua_vs_rust/run.sh Executable file
View File

@ -0,0 +1,27 @@
#!/bin/bash
# cd lua/bench_lua_vs_rust && ./run.sh
set -e
# http://luajit.org/index.html
# cargo clean && \
cargo build --release
export JSONPATH_LIB_PATH="${PWD}/../target/release/deps"
export LUA_PATH="${PWD}/../?.lua;"
echo
time cargo run --release --bin bench -- 1000
echo
time luajit example.lua 1000
echo
time cargo run --release --bin bench -- 5000
echo
time luajit example.lua 5000
echo
time cargo run --release --bin bench -- 10000
echo
time luajit example.lua 10000

View File

@ -0,0 +1,107 @@
lua_package_path '/etc/jsonpath/?.lua;;';
access_log /var/log/access.log;
error_log /var/log/error.log info;
lua_shared_dict jsonpaths 1m;
init_by_lua_block {
local pathStrings = {
"$.store.book[*].author",
"$..author",
"$.store.*",
"$.store..price",
"$..book[2]",
"$..book[-2]",
"$..book[0,1]",
"$..book[:2]",
"$..book[1:2]",
"$..book[-2:]",
"$..book[2:]",
"$..book[?(@.isbn)]",
"$.store.book[?(@.price == 10)]",
"$..*",
"$..book[ ?( (@.price < 13 || $.store.bicycle.price < @.price) && @.price <=10 ) ]",
"$.store.book[?( (@.price < 10 || @.price > 10) && @.price > 10 )]",
"$..[?(@.originPrice > 1)]",
"$.pickBanner[?(@.originPrice > 1)]"
}
local jp = require("jsonpath")
jp.init("/etc/jsonpath/libjsonpath_lib.so")
local jsonpaths = ngx.shared.jsonpaths
for i, path in ipairs(pathStrings) do
jsonpaths:set(i, path)
jp.compile(path)
end
}
server {
listen 80;
server_name localhost;
gzip on;
gzip_types text/plain application/json;
#gzip_comp_level 6;
#gzip_vary on;
location / {
add_header 'Cache-Control' 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
expires off;
default_type 'text/plain';
root /etc/jsonpath/example;
}
location /filter {
# https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Accept-Encoding
proxy_set_header Accept-Encoding "*";
default_type 'text/plain';
rewrite /filter/(.*) /$1 break;
proxy_pass http://localhost;
header_filter_by_lua_block {
ngx.header["content-length"] = nil
local args = ngx.req.get_uri_args()
local jsonpaths = ngx.shared.jsonpaths
local path = jsonpaths:get(args['path'])
if path == nil then
ngx.exit(ngx.HTTP_BAD_REQUEST)
end
}
body_filter_by_lua_block {
local chunk, eof = ngx.arg[1], ngx.arg[2]
local buf = ngx.ctx.buf
if eof then
if buf then
local args = ngx.req.get_uri_args()
local path = ngx.shared.jsonpaths:get(args['path'])
local jsonpath = require("jsonpath")
local template = jsonpath.exec(path)
local json = buf .. chunk
local result = template(json)
ngx.arg[1] = result
return
end
return
end
if buf then
ngx.ctx.buf = buf .. chunk
else
ngx.ctx.buf = chunk
end
ngx.arg[1] = nil
}
}
}

View File

@ -0,0 +1,3 @@
local jsonpath = require("jsonpath")
jsonpath.init("/etc/jsonpath/libjsonpath_lib.so")
ngx.log(ngx.INFO, "loaded libjsonpath_lib.so")

25
lua/docker_example/run.sh Executable file
View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
# cd lua && cargo build --release && cd docker_example && ./run.sh
set -v
[ "$(docker ps -a | grep jsonpath)" ] && docker kill jsonpath
docker run -d --rm --name jsonpath \
-v "${PWD}/../../benchmark/example.json":/etc/jsonpath/example/example.json:ro \
-v "${PWD}/../../benchmark/big_example.json":/etc/jsonpath/example/big_example.json:ro \
-v "${PWD}/../jsonpath.lua":/etc/jsonpath/jsonpath.lua:ro \
-v "${PWD}/init.lua":/etc/jsonpath/init.lua:ro \
-v "${PWD}/../target/release/deps/libjsonpath_lib.so":/etc/jsonpath/libjsonpath_lib.so:ro \
-v "${PWD}/default.conf":/etc/nginx/conf.d/default.conf \
-p 8080:80 \
openresty/openresty:bionic
#for i in {1..16}; do
# curl http://localhost:8080/filter/example.json?path=${i}
# echo
#done
#ab -n 1000 -c 10 http://localhost:8080/filter/big_example.json?path=17
#ab -n 1000 -c 10 http://localhost:8080/filter/big_example.json?path=18

60
lua/jsonpath.lua Normal file
View File

@ -0,0 +1,60 @@
local ffi = require('ffi')
ffi.cdef [[
const char* ffi_select(const char *json_str, const char *path);
void *ffi_path_compile(const char *path);
const char* ffi_select_with_compiled_path(void *ptr, const char *json_str);
]]
local jsonpath
local cache = {}
local module = {}
local function existsVaiable(var)
for k, _ in pairs(_G) do
if k == var then
return true
end
end
end
local _ngx
if existsVaiable('ngx') then
_ngx = ngx
else
_ngx = {}
_ngx.log = function(level, msg)
print('['..level..'] ' .. msg)
end
end
function module.compile(path)
assert(jsonpath, '"libjsonpath_lib" is not loaded')
if(cache[path] == nil) then
cache[path] = jsonpath.ffi_path_compile(path)
_ngx.log(_ngx.INFO, 'compile : [' .. path .. ']')
end
end
function module.exec(path)
local compiledPath = cache[path]
if(cache[path] == nil) then
assert(jsonpath, path .. ": is not compiled")
end
return function(jsonStr)
local result = jsonpath.ffi_select_with_compiled_path(compiledPath, jsonStr)
return ffi.string(result);
end
end
function module.init(path)
if jsonpath == nil then
jsonpath = ffi.load(path)
_ngx.log(_ngx.INFO, '"' .. path .. '" initialized')
end
end
return module

7
nodejs/.gitignore vendored
View File

@ -1,7 +0,0 @@
native/target
native/index.node
native/artifacts.json
**/*~
**/node_modules
.idea
build

View File

@ -1,334 +0,0 @@
# jsonpath-rs
[![Build Status](https://travis-ci.org/freestrings/jsonpath.svg?branch=master)](https://travis-ci.org/freestrings/jsonpath)
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
Pre-built 바이너리는 제공하진 않고 소스를 컴파일해서 설치한다. 만약 Rust가 설치되지 않았다면 자동으로 설치된다.
Build from source instead of using pre-built binary, and if Rust is not installed, the latest version is automatically installed.
> Not yet tested in Windows.
> Supported node version is under v12.0.
## APIs
<details><summary><b>npm package</b></summary>
```javascript
const jsonpath = require('jsonpath-rs');
```
</details>
<details><summary><b>Javascript - jsonpath.Selector class</b></summary>
```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 retObj = selector.select();
console.log(JSON.stringify(ret) == JSON.stringify(retObj));
// => true
```
</details>
<details><summary><b>Javascript - jsonpath.SelectorMut class</b></summary>
빌더 패턴 제약은 `Selector class`와 동일하다.
```javascript
let jsonObj = {
'school': {
'friends': [
{'name': '친구1', 'age': 20},
{'name': '친구2', 'age': 20},
],
},
'friends': [
{'name': '친구3', 'age': 30},
{'name': '친구4'},
],
};
let selector = new jsonpath.SelectorMut();
selector.path('$..[?(@.age == 20)]');
{
selector.value(jsonObj);
selector.deleteValue();
let resultObj = {
'school': {'friends': [null, null]},
'friends': [
{'name': '친구3', 'age': 30},
{'name': '친구4'},
],
};
console.log(JSON.stringify(selector.take()) !== JSON.stringify(resultObj));
// => true
}
{
selector.value(jsonObj);
selector.replaceWith((v) => {
v.age = v.age * 2;
return v;
});
let resultObj = {
'school': {
'friends': [
{'name': '친구1', 'age': 40},
{'name': '친구2', 'age': 40},
],
},
'friends': [
{'name': '친구3', 'age': 30},
{'name': '친구4'},
],
};
console.log(JSON.stringify(selector.take()) !== JSON.stringify(resultObj));
// => true
}
```
</details>
<details><summary><b>Javascript - jsonpath.select(json: string|object, jsonpath: string)</b></summary>
```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
```
</details>
<details><summary><b>Javascript - jsonpath.compile(jsonpath: string)</b></summary>
```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
```
</details>
<details><summary><b>Javascript - jsonpath.selector(json: string|object)</b></summary>
```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
```
</details>
<details><summary><b>Javascript - jsonpath.deleteValue(json: string|object, path: string)</b></summary>
```javascript
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let _1 = jsonpath.deleteValue(jsonObj, '$..friends[0]');
let result = jsonpath.deleteValue(_1, '$..friends[1]');
console.log(JSON.stringify(result) !== JSON.stringify({
"school": { "friends": [null, null]},
"friends": [null, null]
}));
// => true
```
</details>
<details><summary><b>Javascript - jsonpath.replaceWith(json: string|object, path: string, fun: function(json: object) => json: object</b></summary>
```javascript
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let result = jsonpath.replaceWith(jsonObj, '$..friends[0]', (v) => {
v.age = v.age * 2;
return v;
});
console.log(JSON.stringify(result) === JSON.stringify({
"school": {
"friends": [
{"name": "친구1", "age": 40},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 60},
{"name": "친구4"}
]
}));
// => true
```
</details>
[Javascript - Other Examples](https://github.com/freestrings/jsonpath/wiki/Javascript-examples)

View File

@ -1,10 +0,0 @@
#!/bin/bash
if ! [ -x "$(command -v rustc)" ]; then
echo "install rust"
curl https://sh.rustup.rs -sSf > /tmp/rustup.sh
sh /tmp/rustup.sh -y
export PATH="$HOME/.cargo/bin:$PATH"
source "$HOME/.cargo/env"
fi
check-node-version --node '<12.0' && neon build --release

View File

@ -1,149 +0,0 @@
const {
CompileFn,
SelectorFn,
selectStr,
deleteValue: _deleteValue,
replaceWith: _replaceWith,
Selector: _Selector,
SelectorMut: _SelectorMut
} = require('../native');
function compile(path) {
let compile = new CompileFn(path);
return (json) => {
if(typeof json != 'string') {
json = JSON.stringify(json)
}
return JSON.parse(compile.template(json));
};
}
function selector(json) {
if(typeof json != 'string') {
json = JSON.stringify(json)
}
let selector = new SelectorFn(json);
return (path) => {
return JSON.parse(selector.select(path));
}
}
function select(json, path) {
if(typeof json != 'string') {
json = JSON.stringify(json)
}
return JSON.parse(selectStr(json, path));
}
function deleteValue(json, path) {
if(typeof json != 'string') {
json = JSON.stringify(json)
}
return JSON.parse(_deleteValue(json, path));
}
function replaceWith(json, path, fun) {
if(typeof json != 'string') {
json = JSON.stringify(json)
}
let result = _replaceWith(json, path, (v) => {
let result = fun(JSON.parse(v));
if(typeof result != 'string') {
result = JSON.stringify(result)
}
return result;
});
if(typeof result == 'string') {
result = JSON.parse(result);
}
return result;
}
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(json);
return this;
}
select() {
return JSON.parse(this._selector.select());
}
}
class SelectorMut {
constructor() {
return this;
}
path(path) {
this._path = path;
return this;
}
value(json) {
if(typeof json != 'string') {
json = JSON.stringify(json)
}
this._json = json;
return this;
}
deleteValue() {
let selector = new _SelectorMut();
if(!this._path) {
selector.emptyPathError();
return;
}
if(!this._json) {
selector.emptyValueError();
return;
}
this._json = deleteValue(this._json, this._path);
return this;
}
replaceWith(fun) {
let selector = new _SelectorMut();
if(!this._path) {
selector.emptyPathError();
return;
}
if(!this._json) {
selector.emptyValueError();
return;
}
this._json = replaceWith(this._json, this._path, fun);
return this;
}
take() {
let json = this._json;
delete this._json;
return json;
}
}
module.exports = {
compile,
selector,
select,
deleteValue,
replaceWith,
Selector,
SelectorMut
};

View File

@ -1,5 +0,0 @@
.idea/*
.vscode
!.idea/runConfigurations/
/target/
Cargo.lock

View File

@ -1,25 +0,0 @@
[package]
name = "jsonpath4nodejs"
version = "0.2.0"
authors = ["Changseok Han <freestrings@gmail.com>"]
description = "jsonpath_lib bindings for nodejs"
keywords = ["library", "jsonpath", "json", "nodejs"]
repository = "https://github.com/freestrings/jsonpath"
license = "MIT"
build = "build.rs"
exclude = ["artifacts.json", "index.node"]
[build-dependencies]
neon-build = "0.2.0"
[dependencies]
jsonpath_lib = "0.2.0"
#jsonpath_lib = { path = "../../" }
neon = "0.2.0"
neon-serde = "0.1.1"
serde_json = { version = "1.0", features = ["preserve_order"] }
[lib]
name = "jsonpath4nodejs"
crate-type = ["dylib"]

View File

@ -1,7 +0,0 @@
extern crate neon_build;
fn main() {
neon_build::setup(); // must be called in build.rs
// add project-specific build logic here...
}

View File

@ -1,269 +0,0 @@
extern crate jsonpath_lib as jsonpath;
#[macro_use]
extern crate neon;
extern crate neon_serde;
extern crate serde_json;
use jsonpath::{JsonPathError, Node, Parser, Selector};
use neon::prelude::*;
use serde_json::Value;
///
/// `neon_serde::from_value` has very poor performance.
///
fn select(mut ctx: FunctionContext) -> JsResult<JsValue> {
let json_val = ctx.argument::<JsValue>(0)?;
let json: Value = neon_serde::from_value(&mut ctx, json_val)?;
let path = ctx.argument::<JsString>(1)?.value();
match jsonpath::select(&json, path.as_str()) {
Ok(value) => Ok(neon_serde::to_value(&mut ctx, &value)?),
Err(e) => panic!("{:?}", e)
}
}
fn select_str(mut ctx: FunctionContext) -> JsResult<JsValue> {
let json_val = ctx.argument::<JsString>(0)?.value();
let path = ctx.argument::<JsString>(1)?.value();
match jsonpath::select_as_str(&json_val, path.as_str()) {
Ok(value) => Ok(JsString::new(&mut ctx, &value).upcast()),
Err(e) => panic!("{:?}", e)
}
}
fn delete(mut ctx: FunctionContext) -> JsResult<JsValue> {
let json_val = ctx.argument::<JsString>(0)?.value();
let json: Value = match serde_json::from_str(&json_val) {
Ok(value) => value,
Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string()))
};
let path = ctx.argument::<JsString>(1)?.value();
match jsonpath::delete(json, &path) {
Ok(value) => Ok(JsString::new(&mut ctx, match serde_json::to_string(&value) {
Ok(value) => value,
Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string()))
}).upcast()),
Err(e) => panic!("{:?}", e)
}
}
fn replace_with(mut ctx: FunctionContext) -> JsResult<JsValue> {
let json_val = ctx.argument::<JsString>(0)?.value();
let json: Value = match serde_json::from_str(&json_val) {
Ok(value) => value,
Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string()))
};
let path = ctx.argument::<JsString>(1)?.value();
let fun = ctx.argument::<JsFunction>(2)?;
match jsonpath::replace_with(json, &path, &mut |v| {
let json_str = JsString::new(&mut ctx, match serde_json::to_string(v) {
Ok(value) => value,
Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string()))
});
let null = ctx.null();
let args = vec![ctx.string(json_str.value())];
let result = match fun.call(&mut ctx, null, args) {
Ok(result) => result,
Err(e) => panic!("{:?}", e)
};
let json_str = match result.downcast::<JsString>() {
Ok(v) => v.value(),
Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string()))
};
match serde_json::from_str(&json_str) {
Ok(v) => v,
Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string()))
}
}) {
Ok(value) => Ok(JsString::new(&mut ctx, match serde_json::to_string(&value) {
Ok(value) => value,
Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string()))
}).upcast()),
Err(e) => panic!("{:?}", e)
}
}
pub struct SelectorCls {
node: Option<Node>,
value: Option<Value>,
}
impl SelectorCls {
fn path(&mut self, path: &str) {
let node = match Parser::compile(path) {
Ok(node) => node,
Err(e) => panic!("{:?}", e)
};
self.node = Some(node);
}
fn value(&mut self, json_str: &str) {
let value: Value = match serde_json::from_str(&json_str) {
Ok(value) => value,
Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string()))
};
self.value = Some(value);
}
fn select(&self) -> String {
let node = match &self.node {
Some(node) => node,
None => panic!("{:?}", JsonPathError::EmptyPath)
};
let value = match &self.value {
Some(value) => value,
None => panic!("{:?}", JsonPathError::EmptyValue)
};
let mut selector = Selector::new();
selector.compiled_path(node);
selector.value(&value);
match selector.select_as_str() {
Ok(ret) => ret,
Err(e) => panic!("{:?}", e)
}
}
}
pub struct SelectorMutCls {}
declare_types! {
pub class JsCompileFn for SelectorCls {
init(mut ctx) {
let path = ctx.argument::<JsString>(0)?.value();
let node = match Parser::compile(path.as_str()) {
Ok(node) => node,
Err(e) => panic!("{:?}", e)
};
Ok(SelectorCls { node: Some(node), value: None })
}
method template(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 value: Value = match serde_json::from_str(&json_str) {
Ok(value) => value,
Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string()))
};
this.value = Some(value);
};
let result_str = {
let guard = ctx.lock();
let this = this.borrow(&guard);
this.select()
};
Ok(JsString::new(&mut ctx, &result_str).upcast())
}
}
pub class JsSelectorFn for SelectorCls {
init(mut ctx) {
let json_str = ctx.argument::<JsString>(0)?.value();
let value: Value = match serde_json::from_str(&json_str) {
Ok(value) => value,
Err(e) => panic!("{:?}", JsonPathError::Serde(e.to_string()))
};
Ok(SelectorCls { node: None, value: Some(value) })
}
method select(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);
this.path(&path);
}
let result_str = {
let guard = ctx.lock();
let this = this.borrow(&guard);
this.select()
};
Ok(JsString::new(&mut ctx, &result_str).upcast())
}
}
pub class JsSelector for SelectorCls {
init(mut _ctx) {
Ok(SelectorCls { node: None, value: None })
}
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.path(&path);
}
Ok(JsUndefined::new().upcast())
}
method value(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.value(&json_str);
}
Ok(JsUndefined::new().upcast())
}
method select(mut ctx) {
let this = ctx.this();
let result_str = {
let guard = ctx.lock();
let this = this.borrow(&guard);
this.select()
};
Ok(JsString::new(&mut ctx, &result_str).upcast())
}
}
pub class JsSelectorMut for SelectorMutCls {
init(mut _ctx) {
Ok(SelectorMutCls {})
}
method emptyPathError(mut _ctx) {
panic!("{:?}", JsonPathError::EmptyPath);
}
method emptyValueError(mut _ctx) {
panic!("{:?}", JsonPathError::EmptyValue);
}
}
}
register_module!(mut m, {
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_class::<JsSelectorMut>("SelectorMut").expect("SelectorMut class error");
m.export_function("select", select)?;
m.export_function("deleteValue", delete)?;
m.export_function("replaceWith", replace_with)?;
m.export_function("selectStr", select_str)?;
Ok(())
});

1484
nodejs/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,35 +0,0 @@
{
"name": "jsonpath-rs",
"version": "0.2.0",
"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",
"json",
"parsing"
],
"main": "lib/index.js",
"dependencies": {
"check-node-version": "*",
"neon-cli": "^0.2.0"
},
"scripts": {
"install": "./build.sh",
"test": "mocha"
},
"devDependencies": {
"mocha": "^6.1.4"
},
"repository": {
"type": "git",
"url": "git+https://github.com/freestrings/jsonpath.git"
},
"engineStrict": true,
"engines": {
"node": ">=8.0 <12.0"
}
}

View File

@ -1,800 +0,0 @@
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');
let result = template({'a': 1});
if (result[0] === 1) {
done();
}
});
});
describe('selector test', () => {
it('basic', (done) => {
let selector = jsonpath.selector({'a': 1});
let result = selector('$.a');
if (result[0] === 1) {
done();
}
});
});
describe('select test', () => {
it('basic', (done) => {
let result = jsonpath.select({'a': 1}, '$.a');
if (result[0] === 1) {
done();
}
});
});
describe('filter test', () => {
function run(done, path, expected) {
let result = jsonpath.select(jsonObj, path);
if (JSON.stringify(result) === JSON.stringify(expected)) {
done();
}
}
for( var i in list ) {
it(i, (done) => {
run (done, i, list[i]);
})
}
});
describe('SelectorMut test', () => {
it('delete', (done) => {
let jsonObjNew = JSON.parse(JSON.stringify(jsonObj));
let result = jsonpath.deleteValue(jsonObjNew, '$.store.book');
if (JSON.stringify(result) === JSON.stringify({
'store': {
'book': null,
'bicycle': {
'color': 'red',
'price': 19.95,
},
},
'expensive': 10,
})) {
done();
}
});
it('replaceWith', (done) => {
let jsonObjNew = JSON.parse(JSON.stringify(jsonObj));
let result = jsonpath.replaceWith(jsonObjNew, '$.store.book', (v) => {
let ret = v[0];
ret.price = 9;
return ret;
});
if (JSON.stringify(result) === JSON.stringify({
'store': {
'book': {
'category': 'reference',
'author': 'Nigel Rees',
'title': 'Sayings of the Century',
'price': 9,
},
'bicycle': {
'color': 'red',
'price': 19.95,
},
},
'expensive': 10,
})) {
done();
}
});
it('SeletorMut delete', (done) => {
let jsonObjNew = JSON.parse(JSON.stringify(jsonObj));
let selector = new jsonpath.SelectorMut();
selector.path('$.store.book').value(jsonObjNew).deleteValue();
let result = selector.take();
if (JSON.stringify(result) === JSON.stringify({
'store': {
'book': null,
'bicycle': {
'color': 'red',
'price': 19.95,
},
},
'expensive': 10,
})) {
done();
}
});
it('SeletorMut replaceWith', (done) => {
let jsonObjNew = JSON.parse(JSON.stringify(jsonObj));
let selector = new jsonpath.SelectorMut();
selector.path('$.store.book').value(jsonObjNew).replaceWith((v) => {
let ret = v[0];
ret.price = 9;
return ret;
});
let result = selector.take();
if (JSON.stringify(result) === JSON.stringify({
'store': {
'book': {
'category': 'reference',
'author': 'Nigel Rees',
'title': 'Sayings of the Century',
'price': 9,
},
'bicycle': {
'color': 'red',
'price': 19.95,
},
},
'expensive': 10,
})) {
done();
}
});
});
describe('Selector test', () => {
it('select', (done) => {
let selector = new jsonpath.Selector().value(jsonObj);
for(var i in list) {
if(JSON.stringify(list[i]) !== JSON.stringify(selector.path(i).select())) {
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)]').select();
let resultObj = [{"name": "친구3", "age": 30}];
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
throw 'jsonpath.Selector: $..[?(@.age >= 30)]';
}
}
{
let jsonObj = selector.path('$..[?(@.age == 20)]').select();
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} ]}).select();
let resultObj = [{"name": "친구5", "age": 20}];
if(JSON.stringify(jsonObj) !== JSON.stringify(resultObj)) {
throw 'jsonpath.Selector: change value';
}
}
done();
});
it('jsonpath.SelectorMut', (done) => {
let jsonObj = {
'school': {
'friends': [
{'name': '친구1', 'age': 20},
{'name': '친구2', 'age': 20},
],
},
'friends': [
{'name': '친구3', 'age': 30},
{'name': '친구4'},
],
};
let selector = new jsonpath.SelectorMut();
selector.path('$..[?(@.age == 20)]');
{
selector.value(jsonObj).deleteValue();
let resultObj = {
'school': {'friends': [null, null]},
'friends': [
{'name': '친구3', 'age': 30},
{'name': '친구4'},
],
};
if (JSON.stringify(selector.take()) !== JSON.stringify(resultObj)) {
throw 'jsonpath.SelectorMut.deleteValue';
}
}
{
selector.value(jsonObj).replaceWith((v) => {
v.age = v.age * 2;
return v;
});
let resultObj = {
'school': {
'friends': [
{'name': '친구1', 'age': 40},
{'name': '친구2', 'age': 40},
],
},
'friends': [
{'name': '친구3', 'age': 30},
{'name': '친구4'},
],
};
if (JSON.stringify(selector.take()) !== JSON.stringify(resultObj)) {
throw 'jsonpath.SelectorMut.replaceWith';
}
}
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();
});
it('jsonpath.deleteValue(json: string|object, path: string)', (done) => {
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let _1 = jsonpath.deleteValue(jsonObj, '$..friends[0]');
let result = jsonpath.deleteValue(_1, '$..friends[1]');
if(JSON.stringify(result) === JSON.stringify({
"school": { "friends": [null, null]},
"friends": [null, null]
})) {
done();
}
});
it('jsonpath.replaceWith(json: string|object, path: string, fun: function(json: object) => json: object', (done) => {
let jsonObj = {
"school": {
"friends": [
{"name": "친구1", "age": 20},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]
};
let result = jsonpath.replaceWith(jsonObj, '$..friends[0]', (v) => {
v.age = v.age * 2;
return v;
});
if(JSON.stringify(result) === JSON.stringify({
"school": {
"friends": [
{"name": "친구1", "age": 40},
{"name": "친구2", "age": 20}
]
},
"friends": [
{"name": "친구3", "age": 60},
{"name": "친구4"}
]
})) {
done();
}
});
});

59
src/ffi/mod.rs Normal file
View File

@ -0,0 +1,59 @@
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_void};
use {parser, select, select_as_str};
const INVALID_PATH: &str = "invalid path";
const INVALID_JSON: &str = "invalud json";
fn to_str(v: *const c_char, err_msg: &str) -> &str {
unsafe { CStr::from_ptr(v) }.to_str().expect(err_msg)
}
fn to_char_ptr(v: &str) -> *const c_char {
let s = CString::new(v).unwrap_or_else(|_| panic!("invalid string: {}", v));
let ptr = s.as_ptr();
std::mem::forget(s);
ptr
}
#[no_mangle]
pub extern "C" fn ffi_select(json_str: *const c_char, path: *const c_char) -> *const c_char {
let json_str = to_str(json_str, INVALID_JSON);
let path = to_str(path, INVALID_PATH);
match select_as_str(json_str, path) {
Ok(v) => to_char_ptr(v.as_str()),
Err(e) => {
panic!("{:?}", e);
}
}
}
#[no_mangle]
#[allow(clippy::forget_copy)]
pub extern "C" fn ffi_path_compile(path: *const c_char) -> *mut c_void {
let path = to_str(path, INVALID_PATH);
let ref_node = Box::into_raw(Box::new(parser::Parser::compile(path).unwrap()));
let ptr = ref_node as *mut c_void;
std::mem::forget(ref_node);
ptr
}
#[no_mangle]
pub extern "C" fn ffi_select_with_compiled_path(
path_ptr: *mut c_void,
json_ptr: *const c_char,
) -> *const c_char {
let node = unsafe { Box::from_raw(path_ptr as *mut parser::Node) };
let json_str = to_str(json_ptr, INVALID_JSON);
let json = serde_json::from_str(json_str)
.unwrap_or_else(|_| panic!("invalid json string: {}", json_str));
let mut selector = select::Selector::default();
let found = selector.compiled_path(&node).value(&json).select().unwrap();
std::mem::forget(node);
let result = serde_json::to_string(&found)
.unwrap_or_else(|_| panic!("json serialize error: {:?}", found));
to_char_ptr(result.as_str())
}

View File

@ -125,7 +125,6 @@
extern crate array_tool;
extern crate core;
extern crate env_logger;
extern crate indexmap;
#[macro_use]
extern crate log;
extern crate serde;
@ -133,10 +132,12 @@ extern crate serde_json;
use serde_json::Value;
pub use parser::parser::{Node, Parser};
pub use select::{Selector, SelectorMut};
pub use parser::Parser; // TODO private
pub use select::JsonPathError;
pub use select::{Selector, SelectorMut};
#[doc(hidden)]
mod ffi;
#[doc(hidden)]
mod parser;
#[doc(hidden)]
@ -170,15 +171,13 @@ mod select;
/// ]);
/// ```
pub fn compile(path: &str) -> impl FnMut(&Value) -> Result<Vec<&Value>, JsonPathError> {
let node = Parser::compile(path);
move |json| {
match &node {
Ok(node) => {
let mut selector = Selector::new();
selector.compiled_path(node).value(json).select()
}
Err(e) => Err(JsonPathError::Path(e.to_string()))
let node = parser::Parser::compile(path);
move |json| match &node {
Ok(node) => {
let mut selector = Selector::default();
selector.compiled_path(node).value(json).select()
}
Err(e) => Err(JsonPathError::Path(e.to_string())),
}
}
@ -216,12 +215,11 @@ pub fn compile(path: &str) -> impl FnMut(&Value) -> Result<Vec<&Value>, JsonPath
/// &json!({"name": "친구2", "age": 20})
/// ]);
/// ```
pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result<Vec<&Value>, JsonPathError> {
let mut selector = Selector::new();
#[allow(clippy::needless_lifetimes)]
pub fn selector<'a>(json: &'a Value) -> impl FnMut(&str) -> Result<Vec<&'a Value>, JsonPathError> {
let mut selector = Selector::default();
let _ = selector.value(json);
move |path: &str| {
selector.str_path(path)?.reset_value().select()
}
move |path: &str| selector.str_path(path)?.reset_value().select()
}
/// It is the same to `selector` function. but it deserialize the result as given type `T`.
@ -270,12 +268,12 @@ pub fn selector<'a>(json: &'a Value) -> impl FnMut(&'a str) -> Result<Vec<&Value
///
/// assert_eq!(json, ret);
/// ```
pub fn selector_as<T: serde::de::DeserializeOwned>(json: &Value) -> impl FnMut(&str) -> Result<Vec<T>, JsonPathError> + '_ {
let mut selector = Selector::new();
pub fn selector_as<T: serde::de::DeserializeOwned>(
json: &Value,
) -> impl FnMut(&str) -> Result<Vec<T>, JsonPathError> + '_ {
let mut selector = Selector::default();
let _ = selector.value(json);
move |path: &str| {
selector.str_path(path)?.reset_value().select_as()
}
move |path: &str| selector.str_path(path)?.reset_value().select_as()
}
/// It is a simple select function. but it compile the jsonpath argument every time.
@ -303,8 +301,8 @@ pub fn selector_as<T: serde::de::DeserializeOwned>(json: &Value) -> impl FnMut(&
/// &json!({"name": "친구1", "age": 20})
/// ]);
/// ```
pub fn select<'a>(json: &'a Value, path: &'a str) -> Result<Vec<&'a Value>, JsonPathError> {
Selector::new().str_path(path)?.value(json).select()
pub fn select<'a>(json: &'a Value, path: &str) -> Result<Vec<&'a Value>, JsonPathError> {
Selector::default().str_path(path)?.value(json).select()
}
/// It is the same to `select` function but it return the result as string.
@ -332,7 +330,7 @@ pub fn select<'a>(json: &'a Value, path: &'a str) -> Result<Vec<&'a Value>, Json
/// ```
pub fn select_as_str(json_str: &str, path: &str) -> Result<String, JsonPathError> {
let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?;
let ret = Selector::new().str_path(path)?.value(&json).select()?;
let ret = Selector::default().str_path(path)?.value(&json).select()?;
serde_json::to_string(&ret).map_err(|e| JsonPathError::Serde(e.to_string()))
}
@ -374,9 +372,12 @@ pub fn select_as_str(json_str: &str, path: &str) -> Result<String, JsonPathError
///
/// assert_eq!(ret[0], person);
/// ```
pub fn select_as<T: serde::de::DeserializeOwned>(json_str: &str, path: &str) -> Result<Vec<T>, JsonPathError> {
pub fn select_as<T: serde::de::DeserializeOwned>(
json_str: &str,
path: &str,
) -> Result<Vec<T>, JsonPathError> {
let json = serde_json::from_str(json_str).map_err(|e| JsonPathError::Serde(e.to_string()))?;
Selector::new().str_path(path)?.value(&json).select_as()
Selector::default().str_path(path)?.value(&json).select_as()
}
/// Delete(= replace with null) the JSON property using the jsonpath.
@ -412,9 +413,9 @@ pub fn select_as<T: serde::de::DeserializeOwned>(json_str: &str, path: &str) ->
/// ]}));
/// ```
pub fn delete(value: Value, path: &str) -> Result<Value, JsonPathError> {
let mut selector = SelectorMut::new();
let ret = selector.str_path(path)?.value(value).delete()?.take().unwrap_or(Value::Null);
Ok(ret)
let mut selector = SelectorMut::default();
let value = selector.str_path(path)?.value(value).delete()?;
Ok(value.take().unwrap_or(Value::Null))
}
/// Select JSON properties using a jsonpath and transform the result and then replace it. via closure that implements `FnMut` you can transform the selected results.
@ -444,7 +445,7 @@ pub fn delete(value: Value, path: &str) -> Result<Value, JsonPathError> {
/// 0
/// };
///
/// json!(age)
/// Some(json!(age))
/// }).unwrap();
///
/// assert_eq!(ret, json!({
@ -460,9 +461,10 @@ pub fn delete(value: Value, path: &str) -> Result<Value, JsonPathError> {
/// ]}));
/// ```
pub fn replace_with<F>(value: Value, path: &str, fun: &mut F) -> Result<Value, JsonPathError>
where F: FnMut(&Value) -> Value
where
F: FnMut(Value) -> Option<Value>,
{
let mut selector = SelectorMut::new();
let ret = selector.str_path(path)?.value(value).replace_with(fun)?.take().unwrap_or(Value::Null);
Ok(ret)
}
let mut selector = SelectorMut::default();
let value = selector.str_path(path)?.value(value).replace_with(fun)?;
Ok(value.take().unwrap_or(Value::Null))
}

File diff suppressed because it is too large Load Diff

View File

@ -1,726 +0,0 @@
use super::tokenizer::*;
const DUMMY: usize = 0;
type ParseResult<T> = Result<T, String>;
mod utils {
pub fn string_to_isize<F>(string: &String, msg_handler: F) -> Result<isize, String>
where F: Fn() -> String {
match string.as_str().parse::<isize>() {
Ok(n) => Ok(n),
_ => Err(msg_handler())
}
}
pub fn string_to_f64<F>(string: &String, msg_handler: F) -> Result<f64, String>
where F: Fn() -> String {
match string.as_str().parse::<f64>() {
Ok(n) => Ok(n),
_ => Err(msg_handler())
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum ParseToken {
// '$'
Absolute,
// '@'
Relative,
// '.'
In,
// '..'
Leaves,
// '*'
All,
Key(String),
// []
Array,
// 메타토큰
ArrayEof,
// ?( filter )
Filter(FilterToken),
// 1 : 2
Range(Option<isize>, Option<isize>),
// 1, 2, 3
Union(Vec<isize>),
Number(f64),
Bool(bool),
Eof,
}
#[derive(Debug, PartialEq, Clone)]
pub enum FilterToken {
Equal,
NotEqual,
Little,
LittleOrEqual,
Greater,
GreaterOrEqual,
And,
Or,
}
#[derive(Debug, Clone)]
pub struct Node {
left: Option<Box<Node>>,
right: Option<Box<Node>>,
token: ParseToken,
}
pub struct Parser;
impl Parser {
pub fn compile(input: &str) -> ParseResult<Node> {
let mut tokenizer = TokenReader::new(input);
Ok(Self::json_path(&mut tokenizer)?)
}
fn json_path(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#json_path");
match tokenizer.next_token() {
Ok(Token::Absolute(_)) => {
let node = Self::node(ParseToken::Absolute);
Self::paths(node, tokenizer)
}
_ => {
Err(tokenizer.err_msg())
}
}
}
fn paths(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#paths");
match tokenizer.peek_token() {
Ok(Token::Dot(_)) => {
Self::eat_token(tokenizer);
Self::paths_dot(prev, tokenizer)
}
Ok(Token::OpenArray(_)) => {
Self::eat_token(tokenizer);
Self::eat_whitespace(tokenizer);
let node = Self::array(prev, tokenizer)?;
Self::paths(node, tokenizer)
}
_ => {
Ok(prev)
}
}
}
fn paths_dot(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#paths_dot");
let node = Self::path(prev, tokenizer)?;
match tokenizer.peek_token() {
Ok(Token::Equal(_))
| Ok(Token::NotEqual(_))
| Ok(Token::Little(_))
| Ok(Token::LittleOrEqual(_))
| Ok(Token::Greater(_))
| Ok(Token::GreaterOrEqual(_))
| Ok(Token::And(_))
| Ok(Token::Or(_)) => {
Ok(node)
}
_ => {
Self::paths(node, tokenizer)
}
}
}
fn path(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#path");
match tokenizer.peek_token() {
Ok(Token::Dot(_)) => {
Self::path_leaves(prev, tokenizer)
}
Ok(Token::Asterisk(_)) => {
Self::path_in_all(prev, tokenizer)
}
Ok(Token::Key(_, _)) => {
Self::path_in_key(prev, tokenizer)
}
Ok(Token::OpenArray(_)) => {
Self::eat_token(tokenizer);
Self::array(prev, tokenizer)
}
_ => {
Err(tokenizer.err_msg())
}
}
}
fn path_leaves(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#path_leaves");
Self::eat_token(tokenizer);
match tokenizer.peek_token() {
Ok(Token::Asterisk(_)) => {
Self::path_leaves_all(prev, tokenizer)
}
Ok(Token::OpenArray(_)) => {
let mut leaves_node = Self::node(ParseToken::Leaves);
leaves_node.left = Some(Box::new(prev));
Ok(Self::paths(leaves_node, tokenizer)?)
}
_ => {
Self::path_leaves_key(prev, tokenizer)
}
}
}
fn path_leaves_key(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#path_leaves_key");
Ok(Node {
token: ParseToken::Leaves,
left: Some(Box::new(prev)),
right: Some(Box::new(Self::key(tokenizer)?)),
})
}
fn path_leaves_all(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#path_leaves_all");
Self::eat_token(tokenizer);
Ok(Node {
token: ParseToken::Leaves,
left: Some(Box::new(prev)),
right: Some(Box::new(Self::node(ParseToken::All))),
})
}
fn path_in_all(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#path_in_all");
Self::eat_token(tokenizer);
Ok(Node {
token: ParseToken::In,
left: Some(Box::new(prev)),
right: Some(Box::new(Self::node(ParseToken::All))),
})
}
fn path_in_key(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#path_in_key");
Ok(Node {
token: ParseToken::In,
left: Some(Box::new(prev)),
right: Some(Box::new(Self::key(tokenizer)?)),
})
}
fn key(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#key");
match tokenizer.next_token() {
Ok(Token::Key(_, v)) => {
Ok(Self::node(ParseToken::Key(v)))
}
_ => {
Err(tokenizer.err_msg())
}
}
}
fn boolean(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#boolean");
match tokenizer.next_token() {
Ok(Token::Key(_, v)) => {
Ok(Self::node(ParseToken::Bool(v.eq_ignore_ascii_case("true"))))
}
_ => {
Err(tokenizer.err_msg())
}
}
}
fn array_quota_value(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#array_quota_value");
match tokenizer.next_token() {
Ok(Token::SingleQuoted(_, val))
| Ok(Token::DoubleQuoted(_, val)) => {
Ok(Self::node(ParseToken::Key(val)))
}
Err(TokenError::Eof) => {
Ok(Self::node(ParseToken::Eof))
}
_ => {
Err(tokenizer.err_msg())
}
}
}
fn array_start(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#array_start");
match tokenizer.peek_token() {
Ok(Token::Question(_)) => {
Self::eat_token(tokenizer);
Ok(Node {
token: ParseToken::Array,
left: Some(Box::new(prev)),
right: Some(Box::new(Self::filter(tokenizer)?)),
})
}
Ok(Token::Asterisk(_)) => {
Self::eat_token(tokenizer);
Ok(Node {
token: ParseToken::Array,
left: Some(Box::new(prev)),
right: Some(Box::new(Self::node(ParseToken::All))),
})
}
_ => {
Ok(Node {
token: ParseToken::Array,
left: Some(Box::new(prev)),
right: Some(Box::new(Self::array_value(tokenizer)?)),
})
}
}
}
fn array(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#array");
let ret = Self::array_start(prev, tokenizer)?;
Self::eat_whitespace(tokenizer);
Self::close_token(ret, Token::CloseArray(DUMMY), tokenizer)
}
fn array_value_key(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#array_value_key");
match tokenizer.next_token() {
Ok(Token::Key(pos, ref val)) => {
let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?;
Self::eat_whitespace(tokenizer);
match tokenizer.peek_token() {
Ok(Token::Comma(_)) => {
Self::union(digit, tokenizer)
}
Ok(Token::Split(_)) => {
Self::range_from(digit, tokenizer)
}
_ => {
Ok(Self::node(ParseToken::Number(digit as f64)))
}
}
}
_ => {
Err(tokenizer.err_msg())
}
}
}
fn array_value(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#array_value");
match tokenizer.peek_token() {
Ok(Token::Key(_, _)) => {
Self::array_value_key(tokenizer)
}
Ok(Token::Split(_)) => {
Self::eat_token(tokenizer);
Self::range_to(tokenizer)
}
Ok(Token::DoubleQuoted(_, _))
| Ok(Token::SingleQuoted(_, _)) => {
Self::array_quota_value(tokenizer)
}
Err(TokenError::Eof) => {
Ok(Self::node(ParseToken::Eof))
}
_ => {
Self::eat_token(tokenizer);
Err(tokenizer.err_msg())
}
}
}
fn union(num: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#union");
let mut values = vec![num];
while match tokenizer.peek_token() {
Ok(Token::Comma(_)) => true,
_ => false
} {
Self::eat_token(tokenizer);
Self::eat_whitespace(tokenizer);
match tokenizer.next_token() {
Ok(Token::Key(pos, ref val)) => {
let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?;
values.push(digit);
}
_ => {
return Err(tokenizer.err_msg());
}
}
}
Ok(Self::node(ParseToken::Union(values)))
}
fn range_from(num: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#range_from");
Self::eat_token(tokenizer);
Self::eat_whitespace(tokenizer);
match tokenizer.peek_token() {
Ok(Token::Key(_, _)) => {
Self::range(num, tokenizer)
}
_ => {
Ok(Self::node(ParseToken::Range(Some(num), None)))
}
}
}
fn range_to(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#range_to");
match tokenizer.next_token() {
Ok(Token::Key(pos, ref val)) => {
let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?;
Ok(Self::node(ParseToken::Range(None, Some(digit))))
}
_ => {
Err(tokenizer.err_msg())
}
}
}
fn range(num: isize, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#range");
match tokenizer.next_token() {
Ok(Token::Key(pos, ref val)) => {
let digit = utils::string_to_isize(val, || tokenizer.err_msg_with_pos(pos))?;
Ok(Self::node(ParseToken::Range(Some(num), Some(digit))))
}
_ => {
Err(tokenizer.err_msg())
}
}
}
fn filter(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#filter");
match tokenizer.next_token() {
Ok(Token::OpenParenthesis(_)) => {
let ret = Self::exprs(tokenizer)?;
Self::eat_whitespace(tokenizer);
Self::close_token(ret, Token::CloseParenthesis(DUMMY), tokenizer)
}
Err(TokenError::Eof) => {
Ok(Self::node(ParseToken::Eof))
}
_ => {
Err(tokenizer.err_msg())
}
}
}
fn exprs(tokenizer: &mut TokenReader) -> ParseResult<Node> {
Self::eat_whitespace(tokenizer);
debug!("#exprs");
let node = match tokenizer.peek_token() {
Ok(Token::OpenParenthesis(_)) => {
Self::eat_token(tokenizer);
trace!("\t-exprs - open_parenthesis");
let ret = Self::exprs(tokenizer)?;
Self::eat_whitespace(tokenizer);
Self::close_token(ret, Token::CloseParenthesis(DUMMY), tokenizer)?
}
_ => {
trace!("\t-exprs - else");
Self::expr(tokenizer)?
}
};
Self::eat_whitespace(tokenizer);
Self::condition_expr(node, tokenizer)
}
fn condition_expr(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#condition_expr");
match tokenizer.peek_token() {
Ok(Token::And(_)) => {
Self::eat_token(tokenizer);
Ok(Node {
token: ParseToken::Filter(FilterToken::And),
left: Some(Box::new(prev)),
right: Some(Box::new(Self::exprs(tokenizer)?)),
})
}
Ok(Token::Or(_)) => {
Self::eat_token(tokenizer);
Ok(Node {
token: ParseToken::Filter(FilterToken::Or),
left: Some(Box::new(prev)),
right: Some(Box::new(Self::exprs(tokenizer)?)),
})
}
_ => {
Ok(prev)
}
}
}
fn expr(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#expr");
let has_prop_candidate = match tokenizer.peek_token() {
Ok(Token::At(_)) => true,
_ => false
};
let node = Self::term(tokenizer)?;
Self::eat_whitespace(tokenizer);
if match tokenizer.peek_token() {
Ok(Token::Equal(_))
| Ok(Token::NotEqual(_))
| Ok(Token::Little(_))
| Ok(Token::LittleOrEqual(_))
| Ok(Token::Greater(_))
| Ok(Token::GreaterOrEqual(_)) => true,
_ => false
} {
Self::op(node, tokenizer)
} else if has_prop_candidate {
Ok(node)
} else {
return Err(tokenizer.err_msg());
}
}
fn term_num(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#term_num");
match tokenizer.next_token() {
Ok(Token::Key(pos, val)) => {
match tokenizer.peek_token() {
Ok(Token::Dot(_)) => {
Self::term_num_float(val.as_str(), tokenizer)
}
_ => {
let number = utils::string_to_f64(&val, || tokenizer.err_msg_with_pos(pos))?;
Ok(Self::node(ParseToken::Number(number)))
}
}
}
Err(TokenError::Eof) => {
Ok(Self::node(ParseToken::Eof))
}
_ => {
Err(tokenizer.err_msg())
}
}
}
fn term_num_float(mut num: &str, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#term_num_float");
Self::eat_token(tokenizer);
match tokenizer.next_token() {
Ok(Token::Key(pos, frac)) => {
let mut f = String::new();
f.push_str(&mut num);
f.push('.');
f.push_str(frac.as_str());
let number = utils::string_to_f64(&f, || tokenizer.err_msg_with_pos(pos))?;
Ok(Self::node(ParseToken::Number(number)))
}
_ => {
Err(tokenizer.err_msg())
}
}
}
fn peek_key(tokenizer: &mut TokenReader) -> Option<String> {
if let Ok(Token::Key(_, k)) = tokenizer.peek_token() {
Some(k.clone())
} else {
None
}
}
fn term(tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#term");
if tokenizer.peek_is(AT) {
Self::eat_token(tokenizer);
let node = Self::node(ParseToken::Relative);
return match tokenizer.peek_token() {
Ok(Token::Whitespace(_, _)) => {
Self::eat_whitespace(tokenizer);
Ok(node)
}
_ => {
Self::paths(node, tokenizer)
}
};
}
if tokenizer.peek_is(ABSOLUTE) {
return Self::json_path(tokenizer);
}
if tokenizer.peek_is(DOUBLE_QUOTA) || tokenizer.peek_is(SINGLE_QUOTA) {
return Self::array_quota_value(tokenizer);
}
if tokenizer.peek_is(KEY) {
return match Self::peek_key(tokenizer) {
Some(key) => match key.chars().next() {
Some(ch) => match ch {
'-' | '0'...'9' => Self::term_num(tokenizer),
_ => Self::boolean(tokenizer)
}
_ => Err(tokenizer.err_msg())
},
_ => Err(tokenizer.err_msg())
};
}
return Err(tokenizer.err_msg());
}
fn op(prev: Node, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#op");
let token = match tokenizer.next_token() {
Ok(Token::Equal(_)) => {
ParseToken::Filter(FilterToken::Equal)
}
Ok(Token::NotEqual(_)) => {
ParseToken::Filter(FilterToken::NotEqual)
}
Ok(Token::Little(_)) => {
ParseToken::Filter(FilterToken::Little)
}
Ok(Token::LittleOrEqual(_)) => {
ParseToken::Filter(FilterToken::LittleOrEqual)
}
Ok(Token::Greater(_)) => {
ParseToken::Filter(FilterToken::Greater)
}
Ok(Token::GreaterOrEqual(_)) => {
ParseToken::Filter(FilterToken::GreaterOrEqual)
}
Err(TokenError::Eof) => {
ParseToken::Eof
}
_ => {
return Err(tokenizer.err_msg());
}
};
Self::eat_whitespace(tokenizer);
Ok(Node {
token,
left: Some(Box::new(prev)),
right: Some(Box::new(Self::term(tokenizer)?)),
})
}
fn eat_whitespace(tokenizer: &mut TokenReader) {
while let Ok(Token::Whitespace(_, _)) = tokenizer.peek_token() {
let _ = tokenizer.next_token();
}
}
fn eat_token(tokenizer: &mut TokenReader) {
let _ = tokenizer.next_token();
}
fn node(token: ParseToken) -> Node {
Node { left: None, right: None, token }
}
fn close_token(ret: Node, token: Token, tokenizer: &mut TokenReader) -> ParseResult<Node> {
debug!("#close_token");
match tokenizer.next_token() {
Ok(ref t) if t.partial_eq(token) => {
Ok(ret)
}
_ => {
Err(tokenizer.err_msg())
}
}
}
}
pub trait NodeVisitor {
fn visit(&mut self, node: &Node) {
match &node.token {
ParseToken::Absolute
| ParseToken::Relative
| ParseToken::All
| ParseToken::Key(_)
| ParseToken::Range(_, _)
| ParseToken::Union(_)
| ParseToken::Number(_)
| ParseToken::Bool(_) => {
self.visit_token(&node.token);
}
ParseToken::In
| ParseToken::Leaves => {
match &node.left {
Some(n) => self.visit(&*n),
_ => {}
}
self.visit_token(&node.token);
match &node.right {
Some(n) => self.visit(&*n),
_ => {}
}
}
ParseToken::Array => {
match &node.left {
Some(n) => self.visit(&*n),
_ => {}
}
self.visit_token(&node.token);
match &node.right {
Some(n) => self.visit(&*n),
_ => {}
}
self.visit_token(&ParseToken::ArrayEof);
}
ParseToken::Filter(FilterToken::And)
| ParseToken::Filter(FilterToken::Or) => {
match &node.left {
Some(n) => self.visit(&*n),
_ => {}
}
match &node.right {
Some(n) => self.visit(&*n),
_ => {}
}
self.visit_token(&node.token);
}
ParseToken::Filter(_) => {
match &node.left {
Some(n) => self.visit(&*n),
_ => {}
}
self.end_term();
match &node.right {
Some(n) => self.visit(&*n),
_ => {}
}
self.end_term();
self.visit_token(&node.token);
}
_ => {}
}
}
fn visit_token(&mut self, token: &ParseToken);
fn end_term(&mut self) {}
}

View File

@ -12,10 +12,7 @@ pub struct PathReader<'a> {
impl<'a> PathReader<'a> {
pub fn new(input: &'a str) -> Self {
PathReader {
input,
pos: 0,
}
PathReader { input, pos: 0 }
}
pub fn peek_char(&self) -> Result<(usize, char), ReaderError> {
@ -24,8 +21,8 @@ impl<'a> PathReader<'a> {
}
pub fn take_while<F>(&mut self, fun: F) -> Result<(usize, String), ReaderError>
where
F: Fn(&char) -> bool
where
F: Fn(&char) -> bool,
{
let mut char_len: usize = 0;
let mut ret = String::new();
@ -53,4 +50,4 @@ impl<'a> PathReader<'a> {
pub fn current_pos(&self) -> usize {
self.pos
}
}
}

View File

@ -1,31 +1,30 @@
use std::io::Write;
use std::result::Result;
use super::path_reader::{PathReader, ReaderError};
pub const ABSOLUTE: &'static str = "$";
pub const DOT: &'static str = ".";
pub const AT: &'static str = "@";
pub const OPEN_ARRAY: &'static str = "[";
pub const CLOSE_ARRAY: &'static str = "]";
pub const ASTERISK: &'static str = "*";
pub const QUESTION: &'static str = "?";
pub const COMMA: &'static str = ",";
pub const SPLIT: &'static str = ":";
pub const OPEN_PARENTHESIS: &'static str = "(";
pub const CLOSE_PARENTHESIS: &'static str = ")";
pub const KEY: &'static str = "Key";
pub const DOUBLE_QUOTA: &'static str = "\"";
pub const SINGLE_QUOTA: &'static str = "'";
pub const EQUAL: &'static str = "==";
pub const GREATER_OR_EQUAL: &'static str = ">=";
pub const GREATER: &'static str = ">";
pub const LITTLE: &'static str = "<";
pub const LITTLE_OR_EQUAL: &'static str = "<=";
pub const NOT_EQUAL: &'static str = "!=";
pub const AND: &'static str = "&&";
pub const OR: &'static str = "||";
pub const WHITESPACE: &'static str = " ";
pub const ABSOLUTE: &str = "$";
pub const DOT: &str = ".";
pub const AT: &str = "@";
pub const OPEN_ARRAY: &str = "[";
pub const CLOSE_ARRAY: &str = "]";
pub const ASTERISK: &str = "*";
pub const QUESTION: &str = "?";
pub const COMMA: &str = ",";
pub const SPLIT: &str = ":";
pub const OPEN_PARENTHESIS: &str = "(";
pub const CLOSE_PARENTHESIS: &str = ")";
pub const KEY: &str = "Key";
pub const DOUBLE_QUOTE: &str = "\"";
pub const SINGLE_QUOTE: &str = "'";
pub const EQUAL: &str = "==";
pub const GREATER_OR_EQUAL: &str = ">=";
pub const GREATER: &str = ">";
pub const LITTLE: &str = "<";
pub const LITTLE_OR_EQUAL: &str = "<=";
pub const NOT_EQUAL: &str = "!=";
pub const AND: &str = "&&";
pub const OR: &str = "||";
pub const WHITESPACE: &str = " ";
const CH_DOLLA: char = '$';
const CH_DOT: char = '.';
@ -44,8 +43,8 @@ const CH_PIPE: char = '|';
const CH_LITTLE: char = '<';
const CH_GREATER: char = '>';
const CH_EXCLAMATION: char = '!';
const CH_SINGLE_QUOTA: char = '\'';
const CH_DOUBLE_QUOTA: char = '"';
const CH_SINGLE_QUOTE: char = '\'';
const CH_DOUBLE_QUOTE: char = '"';
#[derive(Debug, Clone, PartialEq)]
pub enum TokenError {
@ -55,7 +54,7 @@ pub enum TokenError {
fn to_token_error(read_err: ReaderError) -> TokenError {
match read_err {
ReaderError::Eof => TokenError::Eof
ReaderError::Eof => TokenError::Eof,
}
}
@ -95,6 +94,7 @@ impl Token {
self.to_simple() == str_token
}
#[cfg_attr(tarpaulin, skip)]
fn to_simple(&self) -> &'static str {
match self {
Token::Absolute(_) => ABSOLUTE,
@ -109,8 +109,8 @@ impl Token {
Token::OpenParenthesis(_) => OPEN_PARENTHESIS,
Token::CloseParenthesis(_) => CLOSE_PARENTHESIS,
Token::Key(_, _) => KEY,
Token::DoubleQuoted(_, _) => DOUBLE_QUOTA,
Token::SingleQuoted(_, _) => SINGLE_QUOTA,
Token::DoubleQuoted(_, _) => DOUBLE_QUOTE,
Token::SingleQuoted(_, _) => SINGLE_QUOTE,
Token::Equal(_) => EQUAL,
Token::GreaterOrEqual(_) => GREATER_OR_EQUAL,
Token::Greater(_) => GREATER,
@ -119,7 +119,7 @@ impl Token {
Token::NotEqual(_) => NOT_EQUAL,
Token::And(_) => AND,
Token::Or(_) => OR,
Token::Whitespace(_, _) => WHITESPACE
Token::Whitespace(_, _) => WHITESPACE,
}
}
}
@ -137,7 +137,7 @@ fn simple_matched_token(ch: char, pos: usize) -> Option<Token> {
CH_QUESTION => Some(Token::Question(pos)),
CH_COMMA => Some(Token::Comma(pos)),
CH_SEMICOLON => Some(Token::Split(pos)),
_ => None
_ => None,
}
}
@ -147,20 +147,42 @@ pub struct Tokenizer<'a> {
impl<'a> Tokenizer<'a> {
pub fn new(input: &'a str) -> Self {
trace!("input: {}", input);
Tokenizer {
input: PathReader::new(input),
}
}
fn single_quota(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
let (_, val) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
self.input.next_char().map_err(to_token_error)?;
fn quote(&mut self, ch: char) -> Result<String, TokenError> {
let (_, mut val) = self
.input
.take_while(|c| *c != ch)
.map_err(to_token_error)?;
if let Some('\\') = val.chars().last() {
self.input.next_char().map_err(to_token_error)?;
let _ = val.pop();
let (_, val_remain) = self
.input
.take_while(|c| *c != ch)
.map_err(to_token_error)?;
self.input.next_char().map_err(to_token_error)?;
val.push(ch);
val.push_str(val_remain.as_str());
} else {
self.input.next_char().map_err(to_token_error)?;
}
Ok(val)
}
fn single_quote(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
let val = self.quote(ch)?;
Ok(Token::SingleQuoted(pos, val))
}
fn double_quota(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
let (_, val) = self.input.take_while(|c| *c != ch).map_err(to_token_error)?;
self.input.next_char().map_err(to_token_error)?;
fn double_quote(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
let val = self.quote(ch)?;
Ok(Token::DoubleQuoted(pos, val))
}
@ -171,7 +193,7 @@ impl<'a> Tokenizer<'a> {
self.input.next_char().map_err(to_token_error)?;
Ok(Token::Equal(pos))
}
_ => Err(TokenError::Position(pos))
_ => Err(TokenError::Position(pos)),
}
}
@ -182,7 +204,7 @@ impl<'a> Tokenizer<'a> {
self.input.next_char().map_err(to_token_error)?;
Ok(Token::NotEqual(pos))
}
_ => Err(TokenError::Position(pos))
_ => Err(TokenError::Position(pos)),
}
}
@ -215,7 +237,7 @@ impl<'a> Tokenizer<'a> {
let _ = self.input.next_char().map_err(to_token_error);
Ok(Token::And(pos))
}
_ => Err(TokenError::Position(pos))
_ => Err(TokenError::Position(pos)),
}
}
@ -226,27 +248,31 @@ impl<'a> Tokenizer<'a> {
self.input.next_char().map_err(to_token_error)?;
Ok(Token::Or(pos))
}
_ => Err(TokenError::Position(pos))
_ => Err(TokenError::Position(pos)),
}
}
fn whitespace(&mut self, pos: usize, _: char) -> Result<Token, TokenError> {
let (_, vec) = self.input.take_while(|c| c.is_whitespace()).map_err(to_token_error)?;
let (_, vec) = self
.input
.take_while(|c| c.is_whitespace())
.map_err(to_token_error)?;
Ok(Token::Whitespace(pos, vec.len()))
}
fn other(&mut self, pos: usize, ch: char) -> Result<Token, TokenError> {
let fun = |c: &char| {
match simple_matched_token(*c, pos) {
Some(_) => false,
_ if c == &CH_LITTLE
|| c == &CH_GREATER
|| c == &CH_EQUAL
|| c == &CH_AMPERSAND
|| c == &CH_PIPE
|| c == &CH_EXCLAMATION => false,
_ => !c.is_whitespace()
let fun = |c: &char| match simple_matched_token(*c, pos) {
Some(_) => false,
_ if c == &CH_LITTLE
|| c == &CH_GREATER
|| c == &CH_EQUAL
|| c == &CH_AMPERSAND
|| c == &CH_PIPE
|| c == &CH_EXCLAMATION =>
{
false
}
_ => !c.is_whitespace(),
};
let (_, mut vec) = self.input.take_while(fun).map_err(to_token_error)?;
vec.insert(0, ch);
@ -257,20 +283,18 @@ impl<'a> Tokenizer<'a> {
let (pos, ch) = self.input.next_char().map_err(to_token_error)?;
match simple_matched_token(ch, pos) {
Some(t) => Ok(t),
None => {
match ch {
CH_SINGLE_QUOTA => self.single_quota(pos, ch),
CH_DOUBLE_QUOTA => self.double_quota(pos, ch),
CH_EQUAL => self.equal(pos, ch),
CH_GREATER => self.greater(pos, ch),
CH_LITTLE => self.little(pos, ch),
CH_AMPERSAND => self.and(pos, ch),
CH_PIPE => self.or(pos, ch),
CH_EXCLAMATION => self.not_equal(pos, ch),
_ if ch.is_whitespace() => self.whitespace(pos, ch),
_ => self.other(pos, ch),
}
}
None => match ch {
CH_SINGLE_QUOTE => self.single_quote(pos, ch),
CH_DOUBLE_QUOTE => self.double_quote(pos, ch),
CH_EQUAL => self.equal(pos, ch),
CH_GREATER => self.greater(pos, ch),
CH_LITTLE => self.little(pos, ch),
CH_AMPERSAND => self.and(pos, ch),
CH_PIPE => self.or(pos, ch),
CH_EXCLAMATION => self.not_equal(pos, ch),
_ if ch.is_whitespace() => self.whitespace(pos, ch),
_ => self.other(pos, ch),
},
}
}
@ -298,7 +322,7 @@ impl<'a> TokenReader<'a> {
}
Err(e) => {
return TokenReader {
origin_input: input.clone(),
origin_input: input,
err: e,
err_pos: tokenizer.current_pos(),
tokens,
@ -312,7 +336,7 @@ impl<'a> TokenReader<'a> {
pub fn peek_is(&self, simple_token: &str) -> bool {
match self.peek_token() {
Ok(t) => t.simple_eq(simple_token),
_ => false
_ => false,
}
}
@ -344,23 +368,13 @@ impl<'a> TokenReader<'a> {
}
pub fn err_msg_with_pos(&self, pos: usize) -> String {
let mut w = Vec::new();
writeln!(&mut w, "{}", self.origin_input).unwrap();
writeln!(&mut w, "{}", "^".repeat(pos)).unwrap();
match std::str::from_utf8(&w[..]) {
Ok(s) => s.to_owned(),
Err(_) => panic!("Invalid UTF-8")
}
format!("{}\n{}", self.origin_input, "^".repeat(pos))
}
pub fn err_msg(&self) -> String {
match self.curr_pos {
Some(pos) => {
self.err_msg_with_pos(pos)
}
_ => {
self.err_msg_with_pos(self.err_pos)
}
Some(pos) => self.err_msg_with_pos(pos),
_ => self.err_msg_with_pos(self.err_pos),
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -30,16 +30,27 @@ pub fn read_contents(path: &str) -> String {
}
#[allow(dead_code)]
pub fn select_and_then_compare<'a>(path: &str, json: Value, target: Value) {
let mut s = Selector::new();
let _ = s.str_path(path);
let _ = s.value(&json);
let result = serde_json::to_value(s.select().unwrap()).unwrap();
assert_eq!(result, target, "{}", path);
pub fn select_and_then_compare(path: &str, json: Value, target: Value) {
let mut selector = Selector::default();
let result = selector
.str_path(path)
.unwrap()
.value(&json)
.select_as::<Value>()
.unwrap();
assert_eq!(
result,
match target {
Value::Array(vec) => vec,
_ => panic!("Give me the Array!"),
},
"{}",
path
);
}
#[allow(dead_code)]
pub fn compare_result<'a>(result: Vec<&Value>, target: Value) {
pub fn compare_result(result: Vec<&Value>, target: Value) {
let result = serde_json::to_value(result).unwrap();
assert_eq!(result, target);
}

File diff suppressed because it is too large Load Diff

View File

@ -7,50 +7,77 @@ use serde::Deserialize;
use serde_json::Value;
use common::{compare_result, read_contents, read_json, setup};
use jsonpath::JsonPathError;
mod common;
#[test]
fn compile() {
setup();
let mut template = jsonpath::compile("$..friends[2]");
let json_obj = read_json("./benches/data_obj.json");
let json = template(&json_obj).unwrap();
let ret = json!([
let compile_object = |path| {
let mut template = jsonpath::compile(path);
let json_obj = read_json("./benchmark/data_obj.json");
let json = template(&json_obj).unwrap();
let ret = json!([
{"id": 2,"name": "Gray Berry"},
{"id": 2,"name": "Gray Berry"}
]);
compare_result(json, ret);
compare_result(json, ret);
};
let json_obj = read_json("./benches/data_array.json");
let json = template(&json_obj).unwrap();
let ret = json!([
let compile_array = |path| {
let mut template = jsonpath::compile(path);
let json_obj = read_json("./benchmark/data_array.json");
let json = template(&json_obj).unwrap();
let ret = json!([
{"id": 2,"name": "Gray Berry"},
{"id": 2,"name": "Rosetta Erickson"}
]);
compare_result(json, ret);
compare_result(json, ret);
};
fn compile_error() {
let mut template = jsonpath::compile("$[");
assert!(template(&Value::Null).is_err());
}
setup();
compile_object("$..friends[2]");
compile_array("$..friends[2]");
compile_error();
}
#[test]
fn selector() {
setup();
let json_obj = read_json("./benches/data_obj.json");
let mut reader = jsonpath::selector(&json_obj);
let json = reader("$..friends[2]").unwrap();
let ret = json!([
fn select<'a, F>(selector: &mut F, path: &'a str, target: Value)
where
F: FnMut(&'a str) -> Result<Vec<&Value>, JsonPathError>,
{
let json = selector(path).unwrap();
compare_result(json, target);
};
let json_obj = read_json("./benchmark/data_obj.json");
let mut selector = jsonpath::selector(&json_obj);
select(
&mut selector,
"$..friends[2]",
json!([
{"id": 2,"name": "Gray Berry"},
{"id": 2,"name": "Gray Berry"}
]);
compare_result(json, ret);
let json = reader("$..friends[0]").unwrap();
let ret = json!([
]),
);
select(
&mut selector,
"$..friends[0]",
json!([
{"id": 0},
{"id": 0,"name": "Millicent Norman"}
]);
compare_result(json, ret);
]),
);
}
#[test]
@ -61,49 +88,70 @@ fn selector_as() {
name: Option<String>,
}
let json_obj = read_json("./benches/data_obj.json");
fn select<'a, F>(selector: &mut F, path: &'a str, target: Vec<Friend>)
where
F: FnMut(&'a str) -> Result<Vec<Friend>, JsonPathError>,
{
let json = selector(path).unwrap();
assert_eq!(json, target);
};
let json_obj = read_json("./benchmark/data_obj.json");
let mut selector = jsonpath::selector_as::<Friend>(&json_obj);
let json = selector("$..friends[2]").unwrap();
let ret = vec!(
Friend { id: 2, name: Some("Gray Berry".to_string()) },
Friend { id: 2, name: Some("Gray Berry".to_string()) },
select(
&mut selector,
"$..friends[2]",
vec![
Friend {
id: 2,
name: Some("Gray Berry".to_string()),
},
Friend {
id: 2,
name: Some("Gray Berry".to_string()),
},
],
);
assert_eq!(json, ret);
let json = selector("$..friends[0]").unwrap();
let ret = vec!(
Friend { id: 0, name: None },
Friend { id: 0, name: Some("Millicent Norman".to_string()) },
select(
&mut selector,
"$..friends[0]",
vec![
Friend { id: 0, name: None },
Friend {
id: 0,
name: Some("Millicent Norman".to_string()),
},
],
);
assert_eq!(json, ret);
}
#[test]
fn select() {
let json_obj = read_json("./benches/example.json");
let json_obj = read_json("./benchmark/example.json");
let json = jsonpath::select(&json_obj, "$..book[2]").unwrap();
let ret = json!([{
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
}]);
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
}]);
compare_result(json, ret);
}
#[test]
fn select_str() {
let json_str = read_contents("./benches/example.json");
let json_str = read_contents("./benchmark/example.json");
let result_str = jsonpath::select_as_str(&json_str, "$..book[2]").unwrap();
let ret = json!([{
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
}]);
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
}]);
let json: Value = serde_json::from_str(&result_str).unwrap();
assert_eq!(json, ret);
}
@ -117,7 +165,8 @@ fn test_to_struct() {
phones: Vec<String>,
}
let ret: Vec<Person> = jsonpath::select_as(r#"
let ret: Vec<Person> = jsonpath::select_as(
r#"
{
"person":
{
@ -129,7 +178,10 @@ fn test_to_struct() {
]
}
}
"#, "$.person").unwrap();
"#,
"$.person",
)
.unwrap();
let person = Person {
name: "Doe John".to_string(),
@ -138,4 +190,4 @@ fn test_to_struct() {
};
assert_eq!(vec![person], ret);
}
}

View File

@ -1,40 +0,0 @@
extern crate jsonpath_lib as jsonpath;
#[macro_use]
extern crate serde_json;
use common::{read_json, setup};
use jsonpath::{SelectorMut, Selector};
use serde_json::Value;
mod common;
#[test]
fn selector_mut() {
setup();
let mut selector_mut = SelectorMut::new();
let mut nums = Vec::new();
let result = selector_mut
.str_path(r#"$.store..price"#).unwrap()
.value(read_json("./benches/example.json"))
.replace_with(&mut |v| {
match v {
Value::Number(n) => {
nums.push(n.as_f64().unwrap());
}
_ => {}
}
Value::String("a".to_string())
}).unwrap()
.take().unwrap();
assert_eq!(nums, vec![8.95_f64, 12.99_f64, 8.99_f64, 22.99_f64, 19.95_f64]);
let mut selector = Selector::new();
let result = selector.str_path(r#"$.store..price"#).unwrap()
.value(&result)
.select().unwrap();
assert_eq!(vec![&json!("a"), &json!("a"), &json!("a"), &json!("a"), &json!("a")], result);
}

View File

@ -52,83 +52,105 @@ fn readme() {
let mut selector = jsonpath::selector(&json_obj);
assert_eq!(selector("$.store.book[*].author").unwrap(),
vec![
"Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"
]);
assert_eq!(
selector("$.store.book[*].author").unwrap(),
vec![
"Nigel Rees",
"Evelyn Waugh",
"Herman Melville",
"J. R. R. Tolkien"
]
);
assert_eq!(selector("$..author").unwrap(),
vec![
"Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"
]);
assert_eq!(
selector("$..author").unwrap(),
vec![
"Nigel Rees",
"Evelyn Waugh",
"Herman Melville",
"J. R. R. Tolkien"
]
);
assert_eq!(selector("$.store.*").unwrap(),
vec![
&json!([
{ "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 }
]),
&json!({ "color": "red", "price": 19.95 })
]);
assert_eq!(
selector("$.store.*").unwrap(),
vec![
&json!([
{ "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 }
]),
&json!({ "color": "red", "price": 19.95 })
]
);
assert_eq!(selector("$.store..price").unwrap(),
vec![
8.95, 12.99, 8.99, 22.99, 19.95
]);
assert_eq!(
selector("$.store..price").unwrap(),
vec![8.95, 12.99, 8.99, 22.99, 19.95]
);
assert_eq!(selector("$..book[2]").unwrap(),
vec![
&json!({
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
})
]);
assert_eq!(
selector("$..book[2]").unwrap(),
vec![&json!({
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
})]
);
assert_eq!(selector("$..book[-2]").unwrap(),
vec![
&json!({
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
})
]);
assert_eq!(
selector("$..book[-2]").unwrap(),
vec![&json!({
"category" : "fiction",
"author" : "Herman Melville",
"title" : "Moby Dick",
"isbn" : "0-553-21311-3",
"price" : 8.99
})]
);
assert_eq!(selector("$..book[0,1]").unwrap(),
vec![
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
&json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
]);
assert_eq!(
selector("$..book[0,1]").unwrap(),
vec![
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
&json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
]
);
assert_eq!(selector("$..book[:2]").unwrap(),
vec![
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
&json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
]);
assert_eq!(
selector("$..book[:2]").unwrap(),
vec![
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
&json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
]
);
assert_eq!(selector("$..book[:2]").unwrap(),
vec![
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
&json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
]);
assert_eq!(
selector("$..book[:2]").unwrap(),
vec![
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
&json!({"category" : "fiction","author" : "Evelyn Waugh","title" : "Sword of Honour","price" : 12.99})
]
);
assert_eq!(selector("$..book[?(@.isbn)]").unwrap(),
vec![
&json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}),
&json!({"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99})
]);
assert_eq!(
selector("$..book[?(@.isbn)]").unwrap(),
vec![
&json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99}),
&json!({"category" : "fiction","author" : "J. R. R. Tolkien","title" : "The Lord of the Rings","isbn" : "0-395-19395-8","price" : 22.99})
]
);
assert_eq!(selector("$.store.book[?(@.price < 10)]").unwrap(),
vec![
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
&json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99})
]);
assert_eq!(
selector("$.store.book[?(@.price < 10)]").unwrap(),
vec![
&json!({"category" : "reference","author" : "Nigel Rees","title" : "Sayings of the Century","price" : 8.95}),
&json!({"category" : "fiction","author" : "Herman Melville","title" : "Moby Dick","isbn" : "0-553-21311-3","price" : 8.99})
]
);
}
#[test]
@ -151,12 +173,14 @@ fn readme_selector() {
{"name": "친구4"}
]});
let mut selector = Selector::new();
let mut selector = Selector::default();
let result = selector
.str_path("$..[?(@.age >= 30)]").unwrap()
.str_path("$..[?(@.age >= 30)]")
.unwrap()
.value(&json_obj)
.select().unwrap();
.select()
.unwrap();
assert_eq!(vec![&json!({"name": "친구3", "age": 30})], result);
@ -164,7 +188,13 @@ fn readme_selector() {
assert_eq!(r#"[{"name":"친구3","age":30}]"#, result);
let result = selector.select_as::<Friend>().unwrap();
assert_eq!(vec![Friend { name: "친구3".to_string(), age: Some(30) }], result);
assert_eq!(
vec![Friend {
name: "친구3".to_string(),
age: Some(30)
}],
result
);
}
#[test]
@ -181,10 +211,11 @@ fn readme_selector_mut() {
{"name": "친구4"}
]});
let mut selector_mut = SelectorMut::new();
let mut selector_mut = SelectorMut::default();
let result = selector_mut
.str_path("$..[?(@.age == 20)].age").unwrap()
.str_path("$..[?(@.age == 20)].age")
.unwrap()
.value(json_obj)
.replace_with(&mut |v| {
let age = if let Value::Number(n) = v {
@ -193,21 +224,26 @@ fn readme_selector_mut() {
0
};
json!(age)
}).unwrap()
.take().unwrap();
Some(json!(age))
})
.unwrap()
.take()
.unwrap();
assert_eq!(result, json!({
"school": {
assert_eq!(
result,
json!({
"school": {
"friends": [
{"name": "친구1", "age": 40},
{"name": "친구2", "age": 40}
]
},
"friends": [
{"name": "친구1", "age": 40},
{"name": "친구2", "age": 40}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]}));
{"name": "친구3", "age": 30},
{"name": "친구4"}
]})
);
}
#[test]
@ -226,15 +262,19 @@ fn readme_select() {
let json = jsonpath::select(&json_obj, "$..friends[0]").unwrap();
assert_eq!(json, vec![
&json!({"name": "친구3", "age": 30}),
&json!({"name": "친구1", "age": 20})
]);
assert_eq!(
json,
vec![
&json!({"name": "친구3", "age": 30}),
&json!({"name": "친구1", "age": 20})
]
);
}
#[test]
fn readme_select_as_str() {
let ret = jsonpath::select_as_str(r#"
let ret = jsonpath::select_as_str(
r#"
{
"school": {
"friends": [
@ -247,9 +287,15 @@ fn readme_select_as_str() {
{"name": "친구4"}
]
}
"#, "$..friends[0]").unwrap();
"#,
"$..friends[0]",
)
.unwrap();
assert_eq!(ret, r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#);
assert_eq!(
ret,
r#"[{"name":"친구3","age":30},{"name":"친구1","age":20}]"#
);
}
#[test]
@ -261,19 +307,21 @@ fn readme_select_as() {
phones: Vec<String>,
}
let ret: Vec<Person> = jsonpath::select_as(r#"
{
"person":
{
"name": "Doe John",
"age": 44,
"phones": [
"+44 1234567",
"+44 2345678"
]
}
}
"#, "$.person").unwrap();
let ret: Vec<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(),
@ -302,10 +350,13 @@ fn readme_compile() {
let json = first_firend(&json_obj).unwrap();
assert_eq!(json, vec![
&json!({"name": "친구3", "age": 30}),
&json!({"name": "친구1", "age": 20})
]);
assert_eq!(
json,
vec![
&json!({"name": "친구3", "age": 30}),
&json!({"name": "친구1", "age": 20})
]
);
}
#[test]
@ -326,17 +377,23 @@ fn readme_selector_fn() {
let json = selector("$..friends[0]").unwrap();
assert_eq!(json, vec![
&json!({"name": "친구3", "age": 30}),
&json!({"name": "친구1", "age": 20})
]);
assert_eq!(
json,
vec![
&json!({"name": "친구3", "age": 30}),
&json!({"name": "친구1", "age": 20})
]
);
let json = selector("$..friends[1]").unwrap();
assert_eq!(json, vec![
&json!({"name": "친구4"}),
&json!({"name": "친구2", "age": 20})
]);
assert_eq!(
json,
vec![
&json!({"name": "친구4"}),
&json!({"name": "친구2", "age": 20})
]
);
}
#[test]
@ -363,23 +420,34 @@ fn readme_selector_as() {
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) }
);
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) }
);
let ret = vec![
Friend {
name: "친구4".to_string(),
age: None,
},
Friend {
name: "친구2".to_string(),
age: Some(20),
},
];
assert_eq!(json, ret);
}
#[test]
fn readme_delete() {
let json_obj = json!({
@ -396,37 +464,41 @@ fn readme_delete() {
let ret = jsonpath::delete(json_obj, "$..[?(20 == @.age)]").unwrap();
assert_eq!(ret, json!({
"school": {
assert_eq!(
ret,
json!({
"school": {
"friends": [
null,
null
]
},
"friends": [
null,
null
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]}));
{"name": "친구3", "age": 30},
{"name": "친구4"}
]})
);
}
#[test]
fn readme_delete2() {
let json_obj = common::read_json("./benches/example.json");
let json_obj = common::read_json("./benchmark/example.json");
let ret = jsonpath::delete(json_obj, "$.store.book").unwrap();
println!("{:?}", ret);
assert_eq!(ret, json!({
"store": {
"book": null,
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}));
assert_eq!(
ret,
json!({
"store": {
"book": null,
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
})
);
}
#[test]
@ -450,18 +522,22 @@ fn readme_replace_with() {
0
};
json!(age)
}).unwrap();
Some(json!(age))
})
.unwrap();
assert_eq!(result, json!({
"school": {
assert_eq!(
result,
json!({
"school": {
"friends": [
{"name": "친구1", "age": 40},
{"name": "친구2", "age": 40}
]
},
"friends": [
{"name": "친구1", "age": 40},
{"name": "친구2", "age": 40}
]
},
"friends": [
{"name": "친구3", "age": 30},
{"name": "친구4"}
]}));
}
{"name": "친구3", "age": 30},
{"name": "친구4"}
]})
);
}

131
tests/selector.rs Normal file
View File

@ -0,0 +1,131 @@
extern crate jsonpath_lib as jsonpath;
#[macro_use]
extern crate serde_json;
use common::{read_json, setup};
use jsonpath::{Parser, Selector, SelectorMut};
use serde_json::Value;
mod common;
#[test]
fn selector_mut() {
setup();
let mut selector_mut = SelectorMut::default();
let mut nums = Vec::new();
let result = selector_mut
.str_path(r#"$.store..price"#)
.unwrap()
.value(read_json("./benchmark/example.json"))
.replace_with(&mut |v| {
if let Value::Number(n) = v {
nums.push(n.as_f64().unwrap());
}
Some(Value::String("a".to_string()))
})
.unwrap()
.take()
.unwrap();
assert_eq!(
nums,
vec![8.95_f64, 12.99_f64, 8.99_f64, 22.99_f64, 19.95_f64]
);
let mut selector = Selector::default();
let result = selector
.str_path(r#"$.store..price"#)
.unwrap()
.value(&result)
.select()
.unwrap();
assert_eq!(
vec![
&json!("a"),
&json!("a"),
&json!("a"),
&json!("a"),
&json!("a")
],
result
);
}
#[test]
fn selector_node_ref() {
let node = Parser::compile("$.*").unwrap();
let mut selector = Selector::default();
selector.compiled_path(&node);
assert!(std::ptr::eq(selector.node_ref().unwrap(), &node));
}
#[test]
fn selector_delete() {
setup();
let mut selector_mut = SelectorMut::default();
let result = selector_mut
.str_path(r#"$.store..price[?(@>13)]"#)
.unwrap()
.value(read_json("./benchmark/example.json"))
.delete()
.unwrap()
.take()
.unwrap();
let mut selector = Selector::default();
let result = selector
.str_path(r#"$.store..price"#)
.unwrap()
.value(&result)
.select()
.unwrap();
assert_eq!(
result,
vec![
&json!(8.95),
&json!(12.99),
&json!(8.99),
&Value::Null,
&Value::Null
]
);
}
#[test]
fn selector_remove() {
setup();
let mut selector_mut = SelectorMut::default();
let result = selector_mut
.str_path(r#"$.store..price[?(@>13)]"#)
.unwrap()
.value(read_json("./benchmark/example.json"))
.remove()
.unwrap()
.take()
.unwrap();
let mut selector = Selector::default();
let result = selector
.str_path(r#"$.store..price"#)
.unwrap()
.value(&result)
.select()
.unwrap();
assert_eq!(
result,
vec![
&json!(8.95),
&json!(12.99),
&json!(8.99)
]
);
}

View File

@ -1,6 +1,6 @@
[package]
name = "jsonpath-wasm"
version = "0.2.1"
version = "0.2.4"
authors = ["Changseok Han <freestrings@gmail.com>"]
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"]
@ -14,10 +14,10 @@ crate-type = ["cdylib", "rlib"]
default = ["console_error_panic_hook", "wee_alloc"]
[dependencies]
cfg-if = "0.1.2"
cfg-if = "0.1"
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
console_error_panic_hook = { version = "0.1.1", optional = true }
wee_alloc = { version = "0.4.2", optional = true }
console_error_panic_hook = { version = "0.1", optional = true }
wee_alloc = { version = "0.4", optional = true }
jsonpath_lib = { path = "../" }
serde = "1.0"

View File

@ -1,6 +1,5 @@
import * as jsonpath from "jsonpath-wasm";
let jsonObj = {
"school": {
"friends": [
@ -19,14 +18,21 @@ let ret = [
{"name": "친구1", "age": 20}
];
let selector = new jsonpath.Selector();
selector.path('$..friends[0]');
selector.value(jsonObj);
const path = '$..friends[0]';
let selectToObj = selector.selectTo();
let selectToString = selector.selectToStr();
let ret1 = jsonpath.select(jsonObj, path);
let ret2 = jsonpath.compile(path)(jsonObj);
let ret3 = jsonpath.selector(jsonObj)(path);
let selector = new jsonpath.Selector();
selector.path(path);
selector.value(jsonObj);
let ret4 = selector.select();
console.log(
JSON.stringify(ret) == JSON.stringify(selectToObj),
JSON.stringify(ret) == selectToString
JSON.stringify(ret) == JSON.stringify(ret1),
JSON.stringify(ret) == JSON.stringify(ret2),
JSON.stringify(ret) == JSON.stringify(ret3),
JSON.stringify(ret) == JSON.stringify(ret4)
);

View File

@ -483,12 +483,6 @@
"integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
"dev": true
},
"bluebird": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz",
"integrity": "sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==",
"dev": true
},
"bn.js": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
@ -684,28 +678,6 @@
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
"dev": true
},
"cacache": {
"version": "11.3.2",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz",
"integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==",
"dev": true,
"requires": {
"bluebird": "^3.5.3",
"chownr": "^1.1.1",
"figgy-pudding": "^3.5.1",
"glob": "^7.1.3",
"graceful-fs": "^4.1.15",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.2",
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
}
},
"cache-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
@ -976,22 +948,83 @@
"dev": true
},
"copy-webpack-plugin": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.2.tgz",
"integrity": "sha512-7nC7EynPrnBTtBwwbG1aTqrfNS1aTb9eEjSmQDqFtKAsJrR3uDb+pCDIFT2LzhW+SgGJxQcYzThrmXzzZ720uw==",
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz",
"integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==",
"dev": true,
"requires": {
"cacache": "^11.3.1",
"find-cache-dir": "^2.0.0",
"cacache": "^12.0.3",
"find-cache-dir": "^2.1.0",
"glob-parent": "^3.1.0",
"globby": "^7.1.1",
"is-glob": "^4.0.0",
"loader-utils": "^1.1.0",
"is-glob": "^4.0.1",
"loader-utils": "^1.2.3",
"minimatch": "^3.0.4",
"normalize-path": "^3.0.0",
"p-limit": "^2.1.0",
"serialize-javascript": "^1.4.0",
"p-limit": "^2.2.1",
"schema-utils": "^1.0.0",
"serialize-javascript": "^2.1.2",
"webpack-log": "^2.0.0"
},
"dependencies": {
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
"cacache": {
"version": "12.0.3",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz",
"integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
"dev": true,
"requires": {
"bluebird": "^3.5.5",
"chownr": "^1.1.1",
"figgy-pudding": "^3.5.1",
"glob": "^7.1.4",
"graceful-fs": "^4.1.15",
"infer-owner": "^1.0.3",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.3",
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
}
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"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"
}
},
"p-limit": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
"integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"serialize-javascript": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
"dev": true
}
}
},
"core-util-is": {
@ -2679,6 +2712,12 @@
"integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
"dev": true
},
"infer-owner": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
"integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
"dev": true
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@ -2974,6 +3013,11 @@
}
}
},
"jsonpath-wasm": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/jsonpath-wasm/-/jsonpath-wasm-0.2.4.tgz",
"integrity": "sha512-sxvPEFMpAoNjxUQOkJmVyE3dKX7v4ebX5TkWKguyHteZpHJKlMQbgPKFYL0X3SIU7wAstpOl6hVODLThVmJf1w=="
},
"killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@ -3023,9 +3067,9 @@
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"version": "4.17.14",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
"integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==",
"dev": true
},
"loglevel": {
@ -3237,9 +3281,9 @@
}
},
"mixin-deep": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"dev": true,
"requires": {
"for-in": "^1.0.2",
@ -4107,12 +4151,6 @@
"statuses": "~1.4.0"
}
},
"serialize-javascript": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.6.1.tgz",
"integrity": "sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw==",
"dev": true
},
"serve-index": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
@ -4147,9 +4185,9 @@
"dev": true
},
"set-value": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
@ -4629,46 +4667,107 @@
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
"dev": true
},
"terser": {
"version": "3.17.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz",
"integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==",
"dev": true,
"requires": {
"commander": "^2.19.0",
"source-map": "~0.6.1",
"source-map-support": "~0.5.10"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"terser-webpack-plugin": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz",
"integrity": "sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA==",
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
"integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
"dev": true,
"requires": {
"cacache": "^11.0.2",
"find-cache-dir": "^2.0.0",
"cacache": "^12.0.2",
"find-cache-dir": "^2.1.0",
"is-wsl": "^1.1.0",
"schema-utils": "^1.0.0",
"serialize-javascript": "^1.4.0",
"serialize-javascript": "^2.1.2",
"source-map": "^0.6.1",
"terser": "^3.16.1",
"webpack-sources": "^1.1.0",
"worker-farm": "^1.5.2"
"terser": "^4.1.2",
"webpack-sources": "^1.4.0",
"worker-farm": "^1.7.0"
},
"dependencies": {
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
"cacache": {
"version": "12.0.3",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz",
"integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
"dev": true,
"requires": {
"bluebird": "^3.5.5",
"chownr": "^1.1.1",
"figgy-pudding": "^3.5.1",
"glob": "^7.1.4",
"graceful-fs": "^4.1.15",
"infer-owner": "^1.0.3",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.3",
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
}
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"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"
}
},
"serialize-javascript": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"terser": {
"version": "4.6.3",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.3.tgz",
"integrity": "sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==",
"dev": true,
"requires": {
"commander": "^2.20.0",
"source-map": "~0.6.1",
"source-map-support": "~0.5.12"
}
},
"webpack-sources": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
"integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
"dev": true,
"requires": {
"source-list-map": "^2.0.0",
"source-map": "~0.6.1"
}
},
"worker-farm": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
"integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
"dev": true,
"requires": {
"errno": "~0.1.7"
}
}
}
},
@ -4774,38 +4873,15 @@
"dev": true
},
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
"integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"dev": true,
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
"set-value": "^0.4.3"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"requires": {
"is-extendable": "^0.1.0"
}
},
"set-value": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
"is-plain-object": "^2.0.1",
"to-object-path": "^0.3.0"
}
}
"set-value": "^2.0.1"
}
},
"unique-filename": {
@ -5210,15 +5286,6 @@
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true
},
"worker-farm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz",
"integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==",
"dev": true,
"requires": {
"errno": "~0.1.7"
}
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",

View File

@ -7,9 +7,12 @@
"start": "webpack-dev-server"
},
"devDependencies": {
"copy-webpack-plugin": "^5.0.1",
"copy-webpack-plugin": "^5.1.1",
"webpack": "^4.29.6",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.2.1"
},
"dependencies": {
"jsonpath-wasm": "^0.2.4"
}
}

View File

@ -18,14 +18,20 @@ let ret = [
{"name": "친구1", "age": 20}
];
let selector = new jsonpath.Selector();
selector.path('$..friends[0]');
selector.value(jsonObj);
const path = '$..friends[0]';
let selectToObj = selector.selectTo();
let selectToString = selector.selectToStr();
let ret1 = jsonpath.select(jsonObj, path);
let ret2 = jsonpath.compile(path)(jsonObj);
let ret3 = jsonpath.selector(jsonObj)(path);
let selector = new jsonpath.Selector();
selector.path(path);
selector.value(jsonObj);
let ret4 = selector.select();
console.log(
JSON.stringify(ret) == JSON.stringify(selectToObj),
JSON.stringify(ret) == selectToString
);
JSON.stringify(ret) == JSON.stringify(ret1),
JSON.stringify(ret) == JSON.stringify(ret2),
JSON.stringify(ret) == JSON.stringify(ret3),
JSON.stringify(ret) == JSON.stringify(ret4)
);

View File

@ -0,0 +1,12 @@
{
"name": "jsonpath-wasm-nodejs-example",
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"jsonpath-wasm": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/jsonpath-wasm/-/jsonpath-wasm-0.2.4.tgz",
"integrity": "sha512-sxvPEFMpAoNjxUQOkJmVyE3dKX7v4ebX5TkWKguyHteZpHJKlMQbgPKFYL0X3SIU7wAstpOl6hVODLThVmJf1w=="
}
}
}

View File

@ -4,6 +4,6 @@
"start": "node index.js"
},
"dependencies": {
"jsonpath-wasm": "0"
"jsonpath-wasm": "^0.2.4"
}
}
}

View File

@ -5,9 +5,9 @@ extern crate serde_json;
extern crate wasm_bindgen;
use cfg_if::cfg_if;
use jsonpath::{JsonPathError, Parser};
use jsonpath::Selector as _Selector;
use jsonpath::SelectorMut as _SelectorMut;
use jsonpath::{JsonPathError, Parser};
use serde_json::Value;
use wasm_bindgen::prelude::*;
@ -40,43 +40,40 @@ macro_rules! console_error {
}
fn into_serde_json<D>(js_value: &JsValue) -> Result<D, String>
where D: for<'a> serde::de::Deserialize<'a>
where
D: for<'a> serde::de::Deserialize<'a>,
{
if js_value.is_string() {
match serde_json::from_str(js_value.as_string().unwrap().as_str()) {
Ok(json) => Ok(json),
Err(e) => Err(e.to_string())
Err(e) => Err(e.to_string()),
}
} else {
match js_value.into_serde() {
Ok(json) => Ok(json),
Err(e) => Err(e.to_string())
Err(e) => Err(e.to_string()),
}
}
}
fn replace_fun(v: &Value, fun: &js_sys::Function) -> Value {
match JsValue::from_serde(v) {
Ok(js_v) => {
match fun.call1(&JsValue::NULL, &js_v) {
Ok(result) => {
match into_serde_json(&result) {
Ok(json) => json,
Err(e) => {
console_error!("replace_with - closure returned a invalid JSON: {:?}", e);
Value::Null
}
}
}
fn replace_fun(v: Value, fun: &js_sys::Function) -> Option<Value> {
match JsValue::from_serde(&v) {
Ok(js_v) => match fun.call1(&JsValue::NULL, &js_v) {
Ok(result) => match into_serde_json(&result) {
Ok(json) => Some(json),
Err(e) => {
console_error!("replace_with - fail to call closure: {:?}", e);
Value::Null
console_error!("replace_with - closure returned a invalid JSON: {:?}", e);
Some(Value::Null)
}
},
Err(e) => {
console_error!("replace_with - fail to call closure: {:?}", e);
Some(Value::Null)
}
}
},
Err(e) => {
console_error!("replace_with - invalid JSON object: {:?}", e);
Value::Null
Some(Value::Null)
}
}
}
@ -88,24 +85,24 @@ pub fn compile(path: &str) -> JsValue {
let cb = Closure::wrap(Box::new(move |js_value: JsValue| {
let json = match into_serde_json(&js_value) {
Ok(json) => json,
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e)))
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))),
};
let mut selector = _Selector::new();
match &node {
Ok(node) => selector.compiled_path(node),
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone())))
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e.clone()))),
};
match selector.value(&json).select() {
Ok(ret) => match JsValue::from_serde(&ret) {
Ok(ret) => ret,
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))),
},
Err(e) => JsValue::from_str(&format!("{:?}", e))
Err(e) => JsValue::from_str(&format!("{:?}", e)),
}
}) as Box<Fn(JsValue) -> JsValue>);
}) as Box<dyn Fn(JsValue) -> JsValue>);
let ret = cb.as_ref().clone();
cb.forget();
@ -116,25 +113,27 @@ pub fn compile(path: &str) -> JsValue {
pub fn selector(js_value: JsValue) -> JsValue {
let json: Value = match JsValue::into_serde(&js_value) {
Ok(json) => json,
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))),
};
let cb = Closure::wrap(Box::new(move |path: String| {
match Parser::compile(path.as_str()) {
let cb = Closure::wrap(
Box::new(move |path: String| match Parser::compile(path.as_str()) {
Ok(node) => {
let mut selector = _Selector::new();
let _ = selector.compiled_path(&node);
match selector.value(&json).select() {
Ok(ret) => match JsValue::from_serde(&ret) {
Ok(ret) => ret,
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
Err(e) => {
JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
}
},
Err(e) => JsValue::from_str(&format!("{:?}", e))
Err(e) => JsValue::from_str(&format!("{:?}", e)),
}
}
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Path(e)))
}
}) as Box<Fn(String) -> JsValue>);
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Path(e))),
}) as Box<dyn Fn(String) -> JsValue>,
);
let ret = cb.as_ref().clone();
cb.forget();
@ -145,15 +144,15 @@ pub fn selector(js_value: JsValue) -> JsValue {
pub fn select(js_value: JsValue, path: &str) -> JsValue {
let json = match into_serde_json(&js_value) {
Ok(json) => json,
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e)))
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))),
};
match jsonpath::select(&json, path) {
Ok(ret) => match JsValue::from_serde(&ret) {
Ok(ret) => ret,
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))),
},
Err(e) => JsValue::from_str(&format!("{:?}", e))
Err(e) => JsValue::from_str(&format!("{:?}", e)),
}
}
@ -161,17 +160,15 @@ pub fn select(js_value: JsValue, path: &str) -> JsValue {
pub fn delete(js_value: JsValue, path: &str) -> JsValue {
let json = match into_serde_json(&js_value) {
Ok(json) => json,
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e)))
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))),
};
match jsonpath::delete(json, path) {
Ok(ret) => {
match JsValue::from_serde(&ret) {
Ok(ret) => ret,
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
}
}
Err(e) => JsValue::from_str(&format!("{:?}", e))
Ok(ret) => match JsValue::from_serde(&ret) {
Ok(ret) => ret,
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))),
},
Err(e) => JsValue::from_str(&format!("{:?}", e)),
}
}
@ -179,15 +176,15 @@ pub fn delete(js_value: JsValue, path: &str) -> JsValue {
pub fn replace_with(js_value: JsValue, path: &str, fun: js_sys::Function) -> JsValue {
let json = match into_serde_json(&js_value) {
Ok(json) => json,
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e)))
Err(e) => return JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e))),
};
match jsonpath::replace_with(json, path, &mut |v| replace_fun(v, &fun)) {
Ok(ret) => match JsValue::from_serde(&ret) {
Ok(ret) => ret,
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string())))
Err(e) => JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))),
},
Err(e) => JsValue::from_str(&format!("{:?}", e))
Err(e) => JsValue::from_str(&format!("{:?}", e)),
}
}
@ -196,6 +193,7 @@ pub fn replace_with(js_value: JsValue, path: &str, fun: js_sys::Function) -> JsV
/// lifetime 제약으로 Selector를 사용 할 수 없다.
///
#[wasm_bindgen]
#[derive(Default)]
pub struct Selector {
path: Option<String>,
value: Option<Value>,
@ -205,7 +203,7 @@ pub struct Selector {
impl Selector {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Selector { path: None, value: None }
Selector::default()
}
#[wasm_bindgen(catch)]
@ -227,23 +225,34 @@ impl Selector {
let mut selector = _Selector::new();
if let Some(path) = &self.path {
let _ = selector.str_path(&path).map_err(|e| JsValue::from_str(&format!("{:?}", e)))?;
let _ = selector
.str_path(&path)
.map_err(|e| JsValue::from_str(&format!("{:?}", e)))?;
} else {
return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyPath)));
return Err(JsValue::from_str(&format!(
"{:?}",
JsonPathError::EmptyPath
)));
}
if let Some(value) = &self.value {
let _ = selector.value(value);
} else {
return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyValue)));
return Err(JsValue::from_str(&format!(
"{:?}",
JsonPathError::EmptyValue
)));
}
match selector.select() {
Ok(ret) => match JsValue::from_serde(&ret) {
Ok(ret) => Ok(ret),
Err(e) => Err(JsValue::from_str(&format!("{:?}", JsonPathError::Serde(e.to_string()))))
Err(e) => Err(JsValue::from_str(&format!(
"{:?}",
JsonPathError::Serde(e.to_string())
))),
},
Err(e) => Err(JsValue::from_str(&format!("{:?}", e)))
Err(e) => Err(JsValue::from_str(&format!("{:?}", e))),
}
}
}
@ -252,6 +261,7 @@ impl Selector {
/// `wasm_bindgen` 제약으로 builder-pattern을 구사 할 수 없다.
///
#[wasm_bindgen]
#[derive(Default)]
pub struct SelectorMut {
path: Option<String>,
value: Option<Value>,
@ -261,7 +271,7 @@ pub struct SelectorMut {
impl SelectorMut {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
SelectorMut { path: None, value: None }
SelectorMut::default()
}
#[wasm_bindgen(catch)]
@ -285,13 +295,19 @@ impl SelectorMut {
if let Some(path) = &self.path {
let _ = selector.str_path(path);
} else {
return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyPath)));
return Err(JsValue::from_str(&format!(
"{:?}",
JsonPathError::EmptyPath
)));
};
if let Some(value) = self.value.take() {
selector.value(value);
} else {
return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyValue)));
return Err(JsValue::from_str(&format!(
"{:?}",
JsonPathError::EmptyValue
)));
};
match selector.delete() {
@ -310,13 +326,19 @@ impl SelectorMut {
if let Some(path) = &self.path {
let _ = selector.str_path(path);
} else {
return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyPath)));
return Err(JsValue::from_str(&format!(
"{:?}",
JsonPathError::EmptyPath
)));
};
if let Some(value) = self.value.take() {
selector.value(value);
} else {
return Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyValue)));
return Err(JsValue::from_str(&format!(
"{:?}",
JsonPathError::EmptyValue
)));
};
match selector.replace_with(&mut |v| replace_fun(v, &fun)) {
@ -333,9 +355,12 @@ impl SelectorMut {
match self.value.take() {
Some(ret) => match JsValue::from_serde(&ret) {
Ok(ret) => Ok(ret),
Err(e) => Err(JsValue::from_str(&format!("{:?}", e)))
Err(e) => Err(JsValue::from_str(&format!("{:?}", e))),
},
None => Err(JsValue::from_str(&format!("{:?}", JsonPathError::EmptyValue)))
None => Err(JsValue::from_str(&format!(
"{:?}",
JsonPathError::EmptyValue
))),
}
}
}
}

View File

@ -436,9 +436,9 @@
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"version": "4.17.14",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
"integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==",
"dev": true
},
"log-symbols": {

View File

@ -412,6 +412,79 @@ describe('filter test', () => {
done();
}
});
it('escaped single quote notation', (done) => {
let result = jsonpath.select({"single'quote":"value"}, "$['single\\'quote']");
if (JSON.stringify(result) === JSON.stringify(["value"])) {
done();
}
});
it('escaped double quote notation', (done) => {
let result = jsonpath.select({"single\"quote":"value"}, "$['single\"quote']");
if (JSON.stringify(result) === JSON.stringify(["value"])) {
done();
}
});
it('array range with step - $[::]', (done) => {
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[::]");
if (JSON.stringify(result) === JSON.stringify(["first", "second", "third", "forth", "fifth"])) {
done();
}
});
it('array range with step - $[::2]', (done) => {
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[::2]");
if (JSON.stringify(result) === JSON.stringify(["first", "third", "fifth"])) {
done();
}
});
it('array range with step - $[1: :]', (done) => {
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[1: :]");
if (JSON.stringify(result) === JSON.stringify(["second", "third", "forth", "fifth"])) {
done();
}
});
it('array range with step - $[1:2:]', (done) => {
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[1:2:]");
if (JSON.stringify(result) === JSON.stringify(["second"])) {
done();
}
});
it('array range with step - $[1::2]', (done) => {
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[1::2]");
if (JSON.stringify(result) === JSON.stringify(["second", "forth"])) {
done();
}
});
it('array range with step - $[0:3:1]', (done) => {
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[0:3:1]");
if (JSON.stringify(result) === JSON.stringify(["first", "second", "third"])) {
done();
}
});
it('array range with step - $[0:3:2]', (done) => {
let result = jsonpath.select(["first", "second", "third", "forth", "fifth"], "$[0:3:2]");
if (JSON.stringify(result) === JSON.stringify(["first", "third"])) {
done();
}
});
it('array keys', (done) => {
let result = jsonpath.select({
"key1": "value1",
"key2": 2
}, "$['key1', 'key2']");
if (JSON.stringify(result) === JSON.stringify(["value1", 2])) {
done();
}
});
});
describe('SelectorMut test', () => {
@ -821,4 +894,45 @@ describe('README test', () => {
done();
}
});
});
describe('ISSUE test', () => {
it('Results do not match other implementations #6', (done) => {
let result = jsonpath.select(["first", "second"], "$[:]");
if (JSON.stringify(result) === JSON.stringify(["first", "second"])) {
done();
}
});
it('Invalid wildcard filter results #7', (done) => {
function select(json, expected, paths) {
for (var i = 0 ; i < paths.length ; i++) {
let result = jsonpath.select(json, paths[i]);
if (JSON.stringify(result) !== JSON.stringify(expected)) {
throw Error("Error: " + paths[i]);
}
}
}
select(
["string", 42, { "key": "value" }, [0, 1]],
["string", 42, { "key": "value" }, [0, 1]],
["$.*", "$[*]"]
);
select(
["string", 42, { "key": "value" }, [0, 1]],
[ "string", 42, { "key" : "value" }, [ 0, 1 ], "value", 0, 1 ],
["$..*", "$..[*]"]
);
select(
["string", 42, { "key": "value" }, [0, 1]],
["value", 0, 1],
["$.*.*", "$[*].*", "$.*[*]", "$[*][*]"]
);
done();
});
});

View File

@ -3171,9 +3171,9 @@
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"version": "4.17.14",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
"integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==",
"dev": true
},
"lodash.debounce": {
@ -3402,9 +3402,9 @@
}
},
"mixin-deep": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"dev": true,
"requires": {
"for-in": "^1.0.2",
@ -4335,9 +4335,9 @@
"dev": true
},
"set-value": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
@ -4939,38 +4939,15 @@
"dev": true
},
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
"integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"dev": true,
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
"set-value": "^0.4.3"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"requires": {
"is-extendable": "^0.1.0"
}
},
"set-value": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
"is-plain-object": "^2.0.1",
"to-object-path": "^0.3.0"
}
}
"set-value": "^2.0.1"
}
},
"unique-filename": {

View File

@ -488,12 +488,6 @@
"integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==",
"dev": true
},
"bluebird": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz",
"integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==",
"dev": true
},
"bn.js": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
@ -689,28 +683,6 @@
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
"dev": true
},
"cacache": {
"version": "11.3.2",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz",
"integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==",
"dev": true,
"requires": {
"bluebird": "^3.5.3",
"chownr": "^1.1.1",
"figgy-pudding": "^3.5.1",
"glob": "^7.1.3",
"graceful-fs": "^4.1.15",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.2",
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
}
},
"cache-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
@ -865,12 +837,6 @@
"resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz",
"integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q="
},
"commander": {
"version": "2.17.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
"dev": true
},
"commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
@ -991,21 +957,119 @@
"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.1.1",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz",
"integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==",
"dev": true,
"requires": {
"cacache": "^11.3.1",
"find-cache-dir": "^2.0.0",
"cacache": "^12.0.3",
"find-cache-dir": "^2.1.0",
"glob-parent": "^3.1.0",
"globby": "^7.1.1",
"is-glob": "^4.0.0",
"loader-utils": "^1.1.0",
"is-glob": "^4.0.1",
"loader-utils": "^1.2.3",
"minimatch": "^3.0.4",
"normalize-path": "^3.0.0",
"p-limit": "^2.1.0",
"serialize-javascript": "^1.4.0",
"p-limit": "^2.2.1",
"schema-utils": "^1.0.0",
"serialize-javascript": "^2.1.2",
"webpack-log": "^2.0.0"
},
"dependencies": {
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
"cacache": {
"version": "12.0.3",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz",
"integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
"dev": true,
"requires": {
"bluebird": "^3.5.5",
"chownr": "^1.1.1",
"figgy-pudding": "^3.5.1",
"glob": "^7.1.4",
"graceful-fs": "^4.1.15",
"infer-owner": "^1.0.3",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.3",
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
}
},
"find-cache-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
"integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
"dev": true,
"requires": {
"commondir": "^1.0.1",
"make-dir": "^2.0.0",
"pkg-dir": "^3.0.0"
}
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"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"
}
},
"is-glob": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
"dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
},
"make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
"dev": true,
"requires": {
"pify": "^4.0.1",
"semver": "^5.6.0"
}
},
"p-limit": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
"integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true
},
"serialize-javascript": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
"dev": true
}
}
},
"core-util-is": {
@ -1756,17 +1820,6 @@
"unpipe": "~1.0.0"
}
},
"find-cache-dir": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz",
"integrity": "sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==",
"dev": true,
"requires": {
"commondir": "^1.0.1",
"make-dir": "^1.0.0",
"pkg-dir": "^3.0.0"
}
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
@ -2742,6 +2795,12 @@
"integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
"dev": true
},
"infer-owner": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
"integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
"dev": true
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@ -3142,9 +3201,9 @@
}
},
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"version": "4.17.14",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
"integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==",
"dev": true
},
"loglevel": {
@ -3162,15 +3221,6 @@
"yallist": "^3.0.2"
}
},
"make-dir": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
"dev": true,
"requires": {
"pify": "^3.0.0"
}
},
"mamacro": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz",
@ -3355,9 +3405,9 @@
}
},
"mixin-deep": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
"integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"dev": true,
"requires": {
"for-in": "^1.0.2",
@ -4251,12 +4301,6 @@
"statuses": "~1.4.0"
}
},
"serialize-javascript": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.6.1.tgz",
"integrity": "sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw==",
"dev": true
},
"serve-index": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
@ -4291,9 +4335,9 @@
"dev": true
},
"set-value": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
@ -4550,24 +4594,6 @@
"urix": "^0.1.0"
}
},
"source-map-support": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz",
"integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"source-map-url": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
@ -4817,46 +4843,150 @@
"integrity": "sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA==",
"dev": true
},
"terser": {
"version": "3.16.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-3.16.1.tgz",
"integrity": "sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==",
"dev": true,
"requires": {
"commander": "~2.17.1",
"source-map": "~0.6.1",
"source-map-support": "~0.5.9"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"terser-webpack-plugin": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz",
"integrity": "sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA==",
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz",
"integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==",
"dev": true,
"requires": {
"cacache": "^11.0.2",
"find-cache-dir": "^2.0.0",
"cacache": "^12.0.2",
"find-cache-dir": "^2.1.0",
"is-wsl": "^1.1.0",
"schema-utils": "^1.0.0",
"serialize-javascript": "^1.4.0",
"serialize-javascript": "^2.1.2",
"source-map": "^0.6.1",
"terser": "^3.16.1",
"webpack-sources": "^1.1.0",
"worker-farm": "^1.5.2"
"terser": "^4.1.2",
"webpack-sources": "^1.4.0",
"worker-farm": "^1.7.0"
},
"dependencies": {
"bluebird": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
"dev": true
},
"cacache": {
"version": "12.0.3",
"resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz",
"integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==",
"dev": true,
"requires": {
"bluebird": "^3.5.5",
"chownr": "^1.1.1",
"figgy-pudding": "^3.5.1",
"glob": "^7.1.4",
"graceful-fs": "^4.1.15",
"infer-owner": "^1.0.3",
"lru-cache": "^5.1.1",
"mississippi": "^3.0.0",
"mkdirp": "^0.5.1",
"move-concurrently": "^1.0.1",
"promise-inflight": "^1.0.1",
"rimraf": "^2.6.3",
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
}
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"find-cache-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
"integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
"dev": true,
"requires": {
"commondir": "^1.0.1",
"make-dir": "^2.0.0",
"pkg-dir": "^3.0.0"
}
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"dev": true,
"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"
}
},
"make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
"dev": true,
"requires": {
"pify": "^4.0.1",
"semver": "^5.6.0"
}
},
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true
},
"serialize-javascript": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-support": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
"integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"terser": {
"version": "4.6.3",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.3.tgz",
"integrity": "sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==",
"dev": true,
"requires": {
"commander": "^2.20.0",
"source-map": "~0.6.1",
"source-map-support": "~0.5.12"
}
},
"webpack-sources": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
"integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
"dev": true,
"requires": {
"source-list-map": "^2.0.0",
"source-map": "~0.6.1"
}
},
"worker-farm": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
"integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
"dev": true,
"requires": {
"errno": "~0.1.7"
}
}
}
},
@ -4975,38 +5105,15 @@
"integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk="
},
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
"integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
"dev": true,
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
"set-value": "^0.4.3"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"requires": {
"is-extendable": "^0.1.0"
}
},
"set-value": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
"is-plain-object": "^2.0.1",
"to-object-path": "^0.3.0"
}
}
"set-value": "^2.0.1"
}
},
"unique-filename": {
@ -5454,15 +5561,6 @@
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
},
"worker-farm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz",
"integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==",
"dev": true,
"requires": {
"errno": "~0.1.7"
}
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",

View File

@ -7,7 +7,7 @@
"start": "webpack-dev-server"
},
"devDependencies": {
"copy-webpack-plugin": "^5.0.0",
"copy-webpack-plugin": "^5.1.1",
"webpack": "^4.29.6",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.5"