Skip to content

Commit

Permalink
Merge branch 'main' into asennikov/registering-functions
Browse files Browse the repository at this point in the history
  • Loading branch information
asennikov authored Apr 29, 2024
2 parents 908a885 + e85c1d1 commit 7d3a050
Show file tree
Hide file tree
Showing 13 changed files with 106 additions and 107 deletions.
92 changes: 39 additions & 53 deletions .github/workflows/rust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,57 @@ on:
branches:
- main

name: Test Suite
name: build

jobs:
check:
name: Check
tests:
name: Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- uses: actions-rs/cargo@v1
with:
command: check

test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- uses: actions-rs/cargo@v1
with:
command: test
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --all-features -- --nocapture

test-wasm:
test_wasm:
name: Test WebAssembly (WASI)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
profile: minimal
toolchain: stable
target: wasm32-wasi
override: true
- uses: actions-rs/cargo@v1
- uses: taiki-e/install-action@00a67321d66e038602baf558d366a594a7019ea2
with:
command: install
args: wasmtime-cli cargo-wasi
- uses: actions-rs/cargo@v1
env:
tool: wasmtime,cargo-wasi
- env:
CARGO_TARGET_WASM32_WASI_RUNNER: "wasmtime --dir=."
with:
command: wasi
args: test -- --nocapture
run: cargo wasi test -- --nocapture

clippy:
name: Clippy
fmt_lint:
name: Format/Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: clippy
- uses: actions-rs/cargo@v1
with:
command: clippy
args: -- -D warnings
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cargo fmt
run: cargo fmt --all --check
- name: Cargo clippy
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Check for diffs
run: git diff --ignore-space-at-eol --exit-code

build:
runs-on: ubuntu-latest
needs: [tests, fmt_lint, test_wasm]
# Skipping this results job results in a misleading status on PRs and in the queue,
# so instead lets always return an explicit success or failure.
if: ${{ always() && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }}
steps:
- name: Collect results on success
if: ${{ !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }}
run: echo "All checks passed"
- name: Collect results on failure
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
run: echo "Some checks failed" && false
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.0.0] - 2022-05-28

Initial version published to crates.io.

## [0.1.2] - 2022-05-28

Adding support for base64 encoding decoding, thanks to nated0g for the contribution.
11 changes: 6 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "jsonata-rs"
version = "0.1.0"
version = "0.1.2"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["stedi developers"]
Expand All @@ -12,11 +12,12 @@ categories = ["command-line-utilities", "compilers", "parser-implementations"]

[dependencies]
chrono = "0.4"
clap = { version = "4.4.7", features = ["derive"] }
bitflags = "2.4.1"
bumpalo = { version = "3.9.1", features = ["collections", "boxed"] }
clap = { version = "4.5.4", features = ["derive"] }
bitflags = "2.5.0"
bumpalo = { version = "3.16.0", features = ["collections", "boxed"] }
dtoa = "1"
base64 = "0.22.0"

[dev-dependencies]
test-case = "1.2.0"
test-case = "3.3.1"
test-generator = "0.3"
21 changes: 0 additions & 21 deletions LICENSE-MIT

This file was deleted.

17 changes: 4 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,10 @@ cargo test testsuite

In `tests/testsuite/groups` are the tests groups that are passing, while `tests/testsuite/skip` contains the groups that still require feature implementation. There may be tests in the remaining groups that do pass, but I don't want to split them up - only when a test group fully passes is it moved.

## License

Licensed under either of

- Apache License, Version 2.0
([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license
([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
## Contribution

at your option.
We welcome community contributions and pull requests.

## Contribution
## License

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.
This project is licensed under the Apache-2.0 License. Any code you submit will be released under that license.
1 change: 1 addition & 0 deletions renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"stabilityDays": 21,
"internalChecksFilter": "strict",
"dependencyDashboard": true,
"forkProcessing": "enabled",
"major": {
"automerge": false,
"dependencyDashboardApproval": true,
Expand Down
26 changes: 11 additions & 15 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ pub enum Error {
T2011UpdateNotObject(usize, String),
T2012DeleteNotStrings(usize, String),
T2013BadClone(usize),

// Expression timebox/depth errors
U1001StackOverflow,
U1001Timeout
U1001Timeout,
}

impl error::Error for Error {}
Expand Down Expand Up @@ -131,13 +131,13 @@ impl Error {
Error::T2011UpdateNotObject(..) => "T2011",
Error::T2012DeleteNotStrings(..) => "T2012",
Error::T2013BadClone(..) => "T2013",

// Expression timebox/depth errors
Error::U1001StackOverflow => "U1001",
Error::U1001Timeout => "U1001"
Error::U1001Timeout => "U1001",
}
}
}
}

impl fmt::Display for Error {
#[allow(clippy::many_single_char_names)]
Expand Down Expand Up @@ -182,21 +182,19 @@ impl fmt::Display for Error {
write!(f, "{}: The literal value `{}` cannot be used as a step within a path expression", p, k),
S0214ExpectedVarRight(ref p, ref k) =>
write!(f, "{}: The right side of `{}` must be a variable name (start with $)", p, k),
S0215BindingAfterPredicates(ref p) =>
S0215BindingAfterPredicates(ref p) =>
write!(f, "{}: A context variable binding must precede any predicates on a step", p),
S0216BindingAfterSort(ref p) =>
write!(f, "{}: A context variable binding must precede the 'order-by' clause on a step", p),

// Runtime errors
D1001NumberOfOutRange(ref n) =>
write!(f, "Number out of range: {}", n),
D1001NumberOfOutRange(ref n) => write!(f, "Number out of range: {}", n),
D1002NegatingNonNumeric(ref p, ref v) =>
write!(f, "{}: Cannot negate a non-numeric value `{}`", p, v),
D1009MultipleKeys(ref p, ref k) =>
write!(f, "{}: Multiple key definitions evaluate to same key: {}", p, k),
D2014RangeOutOfBounds(ref p, ref s) =>
write!(f, "{}: The size of the sequence allocated by the range operator (..) must not exceed 1e7. Attempted to allocate {}", p, s),
D3001StringNotFinite(ref p) =>
D3001StringNotFinite(ref p) =>
write!(f, "{}: Attempting to invoke string function on Infinity or NaN", p),
D3030NonNumericCast(ref p, ref n) =>
write!(f, "{}: Unable to cast value to a number: {}", p, n),
Expand All @@ -210,7 +208,6 @@ impl fmt::Display for Error {
write!(f, "{}", m),
D3137Error(ref m) =>
write!(f, "{}", m),

// Type errors
T0410ArgumentNotValid(ref p, ref i, ref t) =>
write!(f, "{}: Argument {} of function {} does not match function signature", p, i, t),
Expand Down Expand Up @@ -246,11 +243,10 @@ impl fmt::Display for Error {
write!(f, "{p}: The delete clause of the transform expression must evaluate to a string or array of strings: {v}"),
T2013BadClone(ref p) =>
write!(f, "{p}: The transform expression clones the input object using the $clone() function. This has been overridden in the current scope by a non-function."),

// Expression timebox/depth errors
U1001StackOverflow =>
U1001StackOverflow =>
write!(f, "Stack overflow error: Check for non-terminating recursive function. Consider rewriting as tail-recursive."),
U1001Timeout =>
U1001Timeout =>
write!(f, "Expression evaluation timeout: Check for infinite loop")
}
}
Expand Down Expand Up @@ -310,4 +306,4 @@ impl fmt::Display for Error {
// "D3136": "The date/time picture string is missing specifiers required to parse the timestamp",
// "D3138": "The $single() function expected exactly 1 matching result. Instead it matched more.",
// "D3139": "The $single() function expected exactly 1 matching result. Instead it matched 0.",
// "D3140": "Malformed URL passed to ${{{functionName}}}(): {{value}}",
// "D3140": "Malformed URL passed to ${{{functionName}}}(): {{value}}",
39 changes: 39 additions & 0 deletions src/evaluator/functions.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use base64::Engine;
use std::borrow::Borrow;

use bumpalo::Bump;
Expand Down Expand Up @@ -912,3 +913,41 @@ where
let right = merge_sort(right.to_vec(), comp)?;
merge(&left, &right, comp)
}

pub fn fn_base64_encode<'a>(
context: FunctionContext<'a, '_>,
args: &'a Value<'a>,
) -> Result<&'a Value<'a>> {
max_args!(context, args, 1);
let arg = &args[0];
if arg.is_undefined() {
return Ok(Value::undefined());
}
assert_arg!(arg.is_string(), context, 1);

let base64 = base64::engine::general_purpose::STANDARD;

let encoded = base64.encode(arg.as_str().as_bytes());

Ok(Value::string(context.arena, encoded))
}

pub fn fn_base64_decode<'a>(
context: FunctionContext<'a, '_>,
args: &'a Value<'a>,
) -> Result<&'a Value<'a>> {
max_args!(context, args, 1);
let arg = &args[0];
if arg.is_undefined() {
return Ok(Value::undefined());
}
assert_arg!(arg.is_string(), context, 1);

let base64 = base64::engine::general_purpose::STANDARD;

let decoded = base64.decode(arg.as_str().as_bytes());
let data = decoded.map_err(|e| Error::D3137Error(e.to_string()))?;
let decoded = String::from_utf8(data).map_err(|e| Error::D3137Error(e.to_string()))?;

Ok(Value::string(context.arena, decoded))
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ impl<'a> JsonAta<'a> {
bind_native!("sum", 1, fn_sum);
bind_native!("trim", 1, fn_trim);
bind_native!("uppercase", 1, fn_uppercase);
bind_native!("base64encode", 1, fn_base64_encode);
bind_native!("base64decode", 1, fn_base64_decode);

let chain_ast = Some(parser::parse(
"function($f, $g) { function($x){ $g($f($x)) } }",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 7d3a050

Please sign in to comment.