mirror of
https://github.com/fluencelabs/jsonpath
synced 2025-07-11 13:41:40 +00:00
Compare commits
99 Commits
Author | SHA1 | Date | |
---|---|---|---|
25cffed2d7 | |||
bab2ff38f7 | |||
ffd87cfbe4 | |||
7597325f59 | |||
2ba3930a8c | |||
844a96b2d1 | |||
3b4d2b4ffc | |||
c2a6f3b319 | |||
8e10128826 | |||
ad39c9e668 | |||
636618e4ac | |||
9fa0f74ce9 | |||
cc5ce6f65f | |||
1152af6c68 | |||
1a54a36cd3 | |||
5b878d7ba7 | |||
d84d0d845c | |||
c3ac7e40e8 | |||
c8ab8ad107 | |||
8c24411c3f | |||
422a23ee57 | |||
b5c5d6b88e | |||
ea7599c012 | |||
9276c0aa02 | |||
2b875c8a7e | |||
6a89553c33 | |||
fe376c4483 | |||
5a52ded4ca | |||
773ea3a3b3 | |||
17a8608392 | |||
e0db04aed9 | |||
d5364ad74a | |||
67991df1f2 | |||
15e6c6065b | |||
fab07adc5a | |||
4b62fcd376 | |||
2daef2c938 | |||
43d092cb35 | |||
19f0878b5a | |||
b2e27b423a | |||
88e6320cf7 | |||
8b85ec9d61 | |||
f5e46882da | |||
53c4711d1a | |||
31612315b8 | |||
2efb019155 | |||
d9b9e9d8bd | |||
c0a5296451 | |||
6c983ced99 | |||
d0f93bde49 | |||
d7423e35da | |||
a23ab7a519 | |||
d4140c8ed5 | |||
595a2d8528 | |||
e8e9dbfe1c | |||
b644c5b0a6 | |||
5c29b54e3a | |||
dde0d5dc2e | |||
a553b4b06b | |||
3d33e8bd08 | |||
8f01598e05 | |||
cab5177811 | |||
9a28faf058 | |||
319186b1d9 | |||
2f0d29d644 | |||
b910ed35f9 | |||
f5717d6d26 | |||
f1fda2af13 | |||
6ad4432737 | |||
13816df970 | |||
030dccc8cc | |||
28ad9c903f | |||
be29571670 | |||
59dad2ea02 | |||
967df1b787 | |||
6d38c67e90 | |||
053be432f2 | |||
d384079842 | |||
5f832e8fe7 | |||
4390feb807 | |||
f536391b71 | |||
c19c75dac5 | |||
ad47444b7a | |||
488e0b400f | |||
fff0e869cb | |||
6a270c9456 | |||
ebd49c2205 | |||
2537469f03 | |||
2e0f78f017 | |||
5d36a0cf15 | |||
a72a13117e | |||
964e0c00f5 | |||
de97e2f95a | |||
74666d264e | |||
51deec66d0 | |||
909c851dcc | |||
b41b9f3aa6 | |||
1a5e8cc025 | |||
5abbfba254 |
7
.idea/runConfigurations/all.xml
generated
7
.idea/runConfigurations/all.xml
generated
@ -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>
|
@ -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 """ />
|
||||
<option name="command" value="test --package jsonpath_lib --test mutable """ />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="nocapture" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
2
.idea/runConfigurations/parser.xml
generated
2
.idea/runConfigurations/parser.xml
generated
@ -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 """ />
|
||||
<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" />
|
||||
|
@ -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 """ />
|
||||
<option name="command" value="test --package jsonpath_lib --test readme """ />
|
||||
<option name="allFeatures" value="false" />
|
||||
<option name="nocapture" value="false" />
|
||||
<option name="backtrace" value="SHORT" />
|
2
.idea/runConfigurations/tokenizer.xml
generated
2
.idea/runConfigurations/tokenizer.xml
generated
@ -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 """ />
|
||||
<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" />
|
||||
|
47
.travis.yml
47
.travis.yml
@ -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
|
19
Cargo.toml
19
Cargo.toml
@ -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
|
57
README.md
57
README.md
@ -2,16 +2,15 @@
|
||||
|
||||
[](https://travis-ci.org/freestrings/jsonpath)
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
`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
9
bench.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
#
|
||||
# rustup default nightly
|
||||
#
|
||||
|
||||
cargo bench --manifest-path ./benchmark/Cargo.toml
|
@ -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
|
3
benches/package-lock.json
generated
3
benches/package-lock.json
generated
@ -1,3 +0,0 @@
|
||||
{
|
||||
"lockfileVersion": 1
|
||||
}
|
4
benchmark/.gitignore
vendored
Normal file
4
benchmark/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
.idea/*
|
||||
.vscode
|
||||
/target/
|
||||
Cargo.lock
|
17
benchmark/Cargo.toml
Normal file
17
benchmark/Cargo.toml
Normal 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"
|
@ -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();
|
||||
}
|
@ -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
4501
benchmark/big_example.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -34,4 +34,4 @@
|
||||
}
|
||||
},
|
||||
"expensive": 10
|
||||
}
|
||||
}
|
@ -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
1
benchmark/src/main.rs
Normal file
@ -0,0 +1 @@
|
||||
fn main() {}
|
15
build.sh
15
build.sh
@ -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
9
coverage.sh
Executable 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
BIN
docs/33fd09cf53124f20b1e8.module.wasm
Normal file
BIN
docs/33fd09cf53124f20b1e8.module.wasm
Normal file
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
docs/bench/33fd09cf53124f20b1e8.module.wasm
Normal file
BIN
docs/bench/33fd09cf53124f20b1e8.module.wasm
Normal file
Binary file not shown.
Binary file not shown.
34
docs/bench/bootstrap.js
vendored
34
docs/bench/bootstrap.js
vendored
@ -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
34
docs/bootstrap.js
vendored
@ -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) {
|
||||
|
@ -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
|
||||
);
|
658
examples/nodejs-rs/package-lock.json
generated
658
examples/nodejs-rs/package-lock.json
generated
@ -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="
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"name": "jsonpath-rs-example",
|
||||
"scripts": {
|
||||
"start": "node index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonpath-rs": "0"
|
||||
}
|
||||
}
|
2
examples/nodejs-wasm/.gitignore
vendored
2
examples/nodejs-wasm/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
node_modules
|
||||
dist
|
5
lua/.gitignore
vendored
Normal file
5
lua/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
.idea/*
|
||||
.vscode
|
||||
/target/
|
||||
Cargo.lock
|
||||
docker_example/ab_results/**
|
14
lua/Cargo.toml
Normal file
14
lua/Cargo.toml
Normal 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"
|
||||
|
22
lua/bench_lua_vs_rust/example.lua
Normal file
22
lua/bench_lua_vs_rust/example.lua
Normal 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
|
46
lua/bench_lua_vs_rust/example.rs
Normal file
46
lua/bench_lua_vs_rust/example.rs
Normal 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
27
lua/bench_lua_vs_rust/run.sh
Executable 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
|
||||
|
107
lua/docker_example/default.conf
Normal file
107
lua/docker_example/default.conf
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
3
lua/docker_example/init.lua
Normal file
3
lua/docker_example/init.lua
Normal 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
25
lua/docker_example/run.sh
Executable 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
60
lua/jsonpath.lua
Normal 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
7
nodejs/.gitignore
vendored
@ -1,7 +0,0 @@
|
||||
native/target
|
||||
native/index.node
|
||||
native/artifacts.json
|
||||
**/*~
|
||||
**/node_modules
|
||||
.idea
|
||||
build
|
334
nodejs/README.md
334
nodejs/README.md
@ -1,334 +0,0 @@
|
||||
# jsonpath-rs
|
||||
|
||||
[](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)
|
@ -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
|
@ -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
|
||||
};
|
5
nodejs/native/.gitignore
vendored
5
nodejs/native/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
.idea/*
|
||||
.vscode
|
||||
!.idea/runConfigurations/
|
||||
/target/
|
||||
Cargo.lock
|
@ -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"]
|
@ -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...
|
||||
}
|
@ -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
1484
nodejs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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"
|
||||
}
|
||||
}
|
@ -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
59
src/ffi/mod.rs
Normal 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())
|
||||
}
|
72
src/lib.rs
72
src/lib.rs
@ -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))
|
||||
}
|
||||
|
1568
src/parser/mod.rs
1568
src/parser/mod.rs
File diff suppressed because it is too large
Load Diff
@ -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) {}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1336
src/select/mod.rs
1336
src/select/mod.rs
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
|
942
tests/filter.rs
942
tests/filter.rs
File diff suppressed because it is too large
Load Diff
152
tests/lib.rs
152
tests/lib.rs
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
402
tests/readme.rs
402
tests/readme.rs
@ -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
131
tests/selector.rs
Normal 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)
|
||||
]
|
||||
);
|
||||
}
|
@ -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"
|
||||
|
@ -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)
|
||||
);
|
||||
|
@ -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",
|
@ -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"
|
||||
}
|
||||
}
|
@ -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)
|
||||
);
|
12
wasm/examples/nodejs-wasm/package-lock.json
generated
Normal file
12
wasm/examples/nodejs-wasm/package-lock.json
generated
Normal 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=="
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,6 @@
|
||||
"start": "node index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonpath-wasm": "0"
|
||||
"jsonpath-wasm": "^0.2.4"
|
||||
}
|
||||
}
|
||||
}
|
149
wasm/src/lib.rs
149
wasm/src/lib.rs
@ -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
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
6
wasm/tests/package-lock.json
generated
6
wasm/tests/package-lock.json
generated
@ -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": {
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
49
wasm/www/package-lock.json
generated
49
wasm/www/package-lock.json
generated
@ -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": {
|
||||
|
418
wasm/www_bench/package-lock.json
generated
418
wasm/www_bench/package-lock.json
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
Reference in New Issue
Block a user