diff --git a/Cargo.lock b/Cargo.lock
index 91c4be6..96b94f2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -141,9 +141,9 @@ dependencies = [
[[package]]
name = "camino"
-version = "1.1.6"
+version = "1.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
+checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
[[package]]
name = "cc"
@@ -362,9 +362,9 @@ checksum = "bbbaaaf38131deb9ca518a274a45bfdb8771f139517b073b16c2d3d32ae5037b"
[[package]]
name = "either"
-version = "1.11.0"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
+checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
[[package]]
name = "env_filter"
@@ -536,6 +536,7 @@ dependencies = [
"libc",
"log",
"num_cpus",
+ "percent-encoding",
"pretty_assertions",
"rand",
"regex",
@@ -569,9 +570,9 @@ checksum = "441225017b106b9f902e97947a6d31e44ebcf274b91bdbfb51e5c477fcd468e5"
[[package]]
name = "libc"
-version = "0.2.154"
+version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libredox"
@@ -585,9 +586,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
-version = "0.4.13"
+version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "log"
@@ -638,6 +639,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
[[package]]
name = "ppv-lite86"
version = "0.2.17"
@@ -843,9 +850,9 @@ dependencies = [
[[package]]
name = "rustversion"
-version = "1.0.16"
+version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0"
+checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
[[package]]
name = "ryu"
@@ -861,22 +868,22 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]]
name = "serde"
-version = "1.0.201"
+version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
+checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.201"
+version = "1.0.202"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
+checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.63",
+ "syn 2.0.64",
]
[[package]]
@@ -929,7 +936,7 @@ dependencies = [
"heck 0.4.1",
"proc-macro2",
"quote",
- "syn 2.0.63",
+ "syn 2.0.64",
]
[[package]]
@@ -987,7 +994,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
- "syn 2.0.63",
+ "syn 2.0.64",
]
[[package]]
@@ -1003,9 +1010,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.63"
+version = "2.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
+checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f"
dependencies = [
"proc-macro2",
"quote",
@@ -1060,22 +1067,22 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.60"
+version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
+checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.60"
+version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
+checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.63",
+ "syn 2.0.64",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 9c200b1..6e3defa 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -36,6 +36,7 @@ lexiclean = "0.0.1"
libc = "0.2.0"
log = "0.4.4"
num_cpus = "1.15.0"
+percent-encoding = "2.3.1"
rand = "0.8.5"
regex = "1.10.4"
semver = "1.0.20"
diff --git a/README.md b/README.md
index 371ab19..8eb3452 100644
--- a/README.md
+++ b/README.md
@@ -1427,6 +1427,9 @@ The process ID is: 420
- `prepend(prefix, s)`master Prepend `prefix` to
whitespace-separated strings in `s`. `prepend('src/', 'foo bar baz')` ā
`'src/foo src/bar src/baz'`
+- `encode_uri_component(s)`master - Percent-encode characters in `s`
+ except `[A-Za-z0-9_.!~*'()-]`, matching the behavior of the
+ [JavaScript `encodeURIComponent` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent).
- `quote(s)` - Replace all single quotes with `'\''` and prepend and append
single quotes to `s`. This is sufficient to escape special characters for
many shells, including most Bourne shell descendants.
diff --git a/src/function.rs b/src/function.rs
index f8fc996..1b657d1 100644
--- a/src/function.rs
+++ b/src/function.rs
@@ -35,6 +35,7 @@ pub(crate) fn get(name: &str) -> Option {
"config_local_directory" => Nullary(|_| dir("local config", dirs::config_local_dir)),
"data_directory" => Nullary(|_| dir("data", dirs::data_dir)),
"data_local_directory" => Nullary(|_| dir("local data", dirs::data_local_dir)),
+ "encode_uri_component" => Unary(encode_uri_component),
"env" => UnaryOpt(env),
"env_var" => Unary(env_var),
"env_var_or_default" => Binary(env_var_or_default),
@@ -204,6 +205,20 @@ fn dir(name: &'static str, f: fn() -> Option) -> Result
}
}
+fn encode_uri_component(_evaluator: &Evaluator, s: &str) -> Result {
+ static PERCENT_ENCODE: percent_encoding::AsciiSet = percent_encoding::NON_ALPHANUMERIC
+ .remove(b'-')
+ .remove(b'_')
+ .remove(b'.')
+ .remove(b'!')
+ .remove(b'~')
+ .remove(b'*')
+ .remove(b'\'')
+ .remove(b'(')
+ .remove(b')');
+ Ok(percent_encoding::utf8_percent_encode(s, &PERCENT_ENCODE).to_string())
+}
+
fn env_var(evaluator: &Evaluator, key: &str) -> Result {
use std::env::VarError::*;
diff --git a/tests/functions.rs b/tests/functions.rs
index e134110..614761a 100644
--- a/tests/functions.rs
+++ b/tests/functions.rs
@@ -793,3 +793,12 @@ fn canonicalize() {
.stdout_regex(".*/justfile")
.run();
}
+
+#[test]
+fn encode_uri_component() {
+ Test::new()
+ .justfile("x := encode_uri_component(\"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\\\"#$%&'()*+,-./:;<=>?@[\\\\]^_`{|}~ \\t\\r\\nš\")")
+ .args(["--evaluate", "x"])
+ .stdout("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!%22%23%24%25%26'()*%2B%2C-.%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E_%60%7B%7C%7D~%20%09%0D%0A%F0%9F%8C%90")
+ .run();
+}