diff --git a/CHANGELOG.md b/CHANGELOG.md
index 34f85b0..a0c52b9 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,11 @@
### v0.8.4
+* New lowercase command #183 (thanks @asvln)
+* New uppercase command #183 (thanks @asvln)
+* New camelcase command #183 (thanks @asvln)
+* New snakecase command #183 (thanks @asvln)
+* New kebabcase command #183 (thanks @asvln)
* Docs - update --collection documentation for json_parse and json_encode commands #175
### v0.8.3 (2021-07-10)
diff --git a/Cargo.lock b/Cargo.lock
index 2846658..c8f7eb1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
+version = 3
+
[[package]]
name = "adler"
version = "1.0.2"
@@ -162,6 +164,7 @@ dependencies = [
"fsio",
"ftp",
"glob",
+ "heck",
"home",
"ignore",
"java-properties",
@@ -346,6 +349,15 @@ dependencies = [
"regex 1.5.4",
]
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
[[package]]
name = "hermit-abi"
version = "0.1.19"
@@ -928,6 +940,12 @@ dependencies = [
"tinyvec",
]
+[[package]]
+name = "unicode-segmentation"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+
[[package]]
name = "unicode-xid"
version = "0.2.2"
diff --git a/docs/sdk.md b/docs/sdk.md
index dd18a08..594e5a4 100644
--- a/docs/sdk.md
+++ b/docs/sdk.md
@@ -145,15 +145,19 @@
* [std::string::Base64Decode (base64_decode)](#std__string__Base64Decode)
* [std::string::Base64Encode (base64_encode)](#std__string__Base64Encode)
* [std::string::BytesToString (bytes_to_string)](#std__string__BytesToString)
+* [std::string::CamelCase (camelcase)](#std__string__CamelCase)
* [std::string::Concat (concat)](#std__string__Concat)
* [std::string::Contains (contains)](#std__string__Contains)
* [std::string::EndsWith (ends_with)](#std__string__EndsWith)
* [std::string::Equals (equals, eq)](#std__string__Equals)
* [std::string::IndexOf (indexof)](#std__string__IndexOf)
* [std::string::IsEmpty (is_empty)](#std__string__IsEmpty)
+* [std::string::KebabCase (kebabcase)](#std__string__KebabCase)
* [std::string::LastIndexOf (last_indexof)](#std__string__LastIndexOf)
* [std::string::Length (length, strlen)](#std__string__Length)
+* [std::string::Lowercase (lowercase)](#std__string__Lowercase)
* [std::string::Replace (replace)](#std__string__Replace)
+* [std::string::SnakeCase (snakecase)](#std__string__SnakeCase)
* [std::string::Split (split)](#std__string__Split)
* [std::string::StartsWith (starts_with)](#std__string__StartsWith)
* [std::string::StringToBytes (string_to_bytes)](#std__string__StringToBytes)
@@ -161,6 +165,7 @@
* [std::string::Trim (trim)](#std__string__Trim)
* [std::string::TrimEnd (trim_end)](#std__string__TrimEnd)
* [std::string::TrimStart (trim_start)](#std__string__TrimStart)
+* [std::string::Uppercase (uppercase)](#std__string__Uppercase)
* [std::test::Assert (assert)](#std__test__Assert)
* [std::test::AssertEquals (assert_eq)](#std__test__AssertEquals)
* [std::test::AssertError (assert_error)](#std__test__AssertError)
@@ -5455,6 +5460,35 @@ assert_eq ${text} "hello world"
#### Aliases:
bytes_to_string
+
+## std::string::CamelCase
+```sh
+var = camelcase text
+```
+
+Converts the provided string into camel case.
+All non-alphanumeric characters are ignored.
+
+#### Parameters
+
+The string to convert.
+
+#### Return Value
+
+The converted string.
+
+#### Examples
+
+```sh
+string = camelcase "hello, world!"
+assert_eq ${string} "HelloWorld"
+```
+
+
+
+#### Aliases:
+camelcase
+
## std::string::Concat
@@ -5657,6 +5691,35 @@ empty = is_empty ${value}
#### Aliases:
is_empty
+
+## std::string::KebabCase
+```sh
+var = kebobcase text
+```
+
+Converts the provided string into kebob case.
+All non-alphanumeric characters are ignored.
+
+#### Parameters
+
+The string to convert.
+
+#### Return Value
+
+The converted string.
+
+#### Examples
+
+```sh
+string = kebobcase "Hello, World!"
+assert_eq ${string} "hello-world"
+```
+
+
+
+#### Aliases:
+kebabcase
+
## std::string::LastIndexOf
```sh
@@ -5712,6 +5775,34 @@ len = length "Hello World"
#### Aliases:
length, strlen
+
+## std::string::Lowercase
+```sh
+var = lowercase text
+```
+
+Converts the provided string into lowercase.
+
+#### Parameters
+
+The string to convert.
+
+#### Return Value
+
+The converted string.
+
+#### Examples
+
+```sh
+string = lowercase "Hello World"
+assert_eq ${string} "hello world"
+```
+
+
+
+#### Aliases:
+lowercase
+
## std::string::Replace
```sh
@@ -5743,6 +5834,35 @@ assert_eq ${updated} "my large stuff value with lots of stuff"
#### Aliases:
replace
+
+## std::string::SnakeCase
+```sh
+var = snakecase text
+```
+
+Converts the provided string into snake case.
+All non-alphanumeric characters are ignored.
+
+#### Parameters
+
+The string to convert.
+
+#### Return Value
+
+The converted string.
+
+#### Examples
+
+```sh
+string = snakecase "Hello, World!"
+assert_eq ${string} "hello_world"
+```
+
+
+
+#### Aliases:
+snakecase
+
## std::string::Split
```sh
@@ -5983,6 +6103,34 @@ trimmed = trim_start " some text "
#### Aliases:
trim_start
+
+## std::string::Uppercase
+```sh
+var = uppercase text
+```
+
+Converts the provided string into uppercase.
+
+#### Parameters
+
+The string to convert.
+
+#### Return Value
+
+The converted string.
+
+#### Examples
+
+```sh
+string = uppercase "Hello World"
+assert_eq ${string} "HELLO WORLD"
+```
+
+
+
+#### Aliases:
+uppercase
+
## std::test::Assert
```sh
diff --git a/duckscript/src/lib.rs b/duckscript/src/lib.rs
index 6359132..222d5a3 100755
--- a/duckscript/src/lib.rs
+++ b/duckscript/src/lib.rs
@@ -5,8 +5,8 @@
arithmetic_overflow,
array_into_iter,
asm_sub_register,
+ bad_asm_style,
bindings_with_variant_name,
- broken_intra_doc_links,
cenum_impl_drop_cast,
clashing_extern_declarations,
coherence_leak_check,
@@ -18,10 +18,13 @@
dead_code,
deprecated,
deprecated_in_future,
+ deref_nullptr,
drop_bounds,
+ dyn_drop,
ellipsis_inclusive_range_patterns,
explicit_outlives_requirements,
exported_private_dependencies,
+ forbidden_lint_groups,
function_item_references,
ill_formed_attribute_input,
illegal_floating_point_literal_pattern,
@@ -30,18 +33,20 @@
incomplete_features,
incomplete_include,
indirect_structural_match,
+ ineffective_unstable_trait_impl,
inline_no_sanitize,
- invalid_codeblock_attributes,
+ invalid_doc_attributes,
invalid_type_param_default,
invalid_value,
irrefutable_let_patterns,
keyword_idents,
+ large_assignments,
late_bound_lifetime_arguments,
+ legacy_derive_helpers,
macro_expanded_macro_exports_accessed_by_absolute_paths,
meta_variable_misuse,
missing_abi,
missing_copy_implementations,
- missing_crate_level_docs,
missing_docs,
missing_fragment_specifier,
mixed_script_confusables,
@@ -50,26 +55,29 @@
no_mangle_const_items,
no_mangle_generic_items,
non_ascii_idents,
- non_autolinks,
non_camel_case_types,
+ non_fmt_panics,
non_shorthand_field_patterns,
non_snake_case,
non_upper_case_globals,
nontrivial_structural_match,
+ noop_method_call,
order_dependent_trait_objects,
overflowing_literals,
overlapping_range_endpoints,
- panic_fmt,
path_statements,
patterns_in_fns_without_body,
pointer_structural_match,
- private_doc_tests,
private_in_public,
- private_intra_doc_links,
+ proc_macro_back_compat,
proc_macro_derive_resolution_fallback,
pub_use_of_private_extern_crate,
redundant_semicolons,
- safe_packed_borrows,
+ rust_2021_incompatible_closure_captures,
+ rust_2021_incompatible_or_patterns,
+ rust_2021_prefixes_incompatible_syntax,
+ rust_2021_prelude_collisions,
+ semicolon_in_expressions_from_macros,
soft_unstable,
stable_features,
temporary_cstring_as_ptr,
@@ -89,8 +97,10 @@
unreachable_patterns,
unreachable_pub,
unsafe_code,
+ unsafe_op_in_unsafe_fn,
unstable_features,
unstable_name_collisions,
+ unsupported_calling_conventions,
unsupported_naked_functions,
unused_allocation,
unused_assignments,
@@ -112,17 +122,13 @@
unused_qualifications,
unused_unsafe,
unused_variables,
- useless_deprecated,
- where_clauses_object_safety,
- while_true
+ useless_deprecated
)]
#![warn(macro_use_extern_crate, unknown_lints)]
#![allow(
bare_trait_objects,
box_pointers,
elided_lifetimes_in_paths,
- invalid_html_tags,
- missing_doc_code_examples,
missing_debug_implementations,
single_use_lifetimes,
unused_results,
diff --git a/duckscript_cli/src/main.rs b/duckscript_cli/src/main.rs
index 12bb785..f4681d7 100755
--- a/duckscript_cli/src/main.rs
+++ b/duckscript_cli/src/main.rs
@@ -5,8 +5,8 @@
arithmetic_overflow,
array_into_iter,
asm_sub_register,
+ bad_asm_style,
bindings_with_variant_name,
- broken_intra_doc_links,
cenum_impl_drop_cast,
clashing_extern_declarations,
coherence_leak_check,
@@ -18,10 +18,13 @@
dead_code,
deprecated,
deprecated_in_future,
+ deref_nullptr,
drop_bounds,
+ dyn_drop,
ellipsis_inclusive_range_patterns,
explicit_outlives_requirements,
exported_private_dependencies,
+ forbidden_lint_groups,
function_item_references,
ill_formed_attribute_input,
illegal_floating_point_literal_pattern,
@@ -30,18 +33,20 @@
incomplete_features,
incomplete_include,
indirect_structural_match,
+ ineffective_unstable_trait_impl,
inline_no_sanitize,
- invalid_codeblock_attributes,
+ invalid_doc_attributes,
invalid_type_param_default,
invalid_value,
irrefutable_let_patterns,
keyword_idents,
+ large_assignments,
late_bound_lifetime_arguments,
+ legacy_derive_helpers,
macro_expanded_macro_exports_accessed_by_absolute_paths,
meta_variable_misuse,
missing_abi,
missing_copy_implementations,
- missing_crate_level_docs,
missing_docs,
missing_fragment_specifier,
mixed_script_confusables,
@@ -50,26 +55,29 @@
no_mangle_const_items,
no_mangle_generic_items,
non_ascii_idents,
- non_autolinks,
non_camel_case_types,
+ non_fmt_panics,
non_shorthand_field_patterns,
non_snake_case,
non_upper_case_globals,
nontrivial_structural_match,
+ noop_method_call,
order_dependent_trait_objects,
overflowing_literals,
overlapping_range_endpoints,
- panic_fmt,
path_statements,
patterns_in_fns_without_body,
pointer_structural_match,
- private_doc_tests,
private_in_public,
- private_intra_doc_links,
+ proc_macro_back_compat,
proc_macro_derive_resolution_fallback,
pub_use_of_private_extern_crate,
redundant_semicolons,
- safe_packed_borrows,
+ rust_2021_incompatible_closure_captures,
+ rust_2021_incompatible_or_patterns,
+ rust_2021_prefixes_incompatible_syntax,
+ rust_2021_prelude_collisions,
+ semicolon_in_expressions_from_macros,
soft_unstable,
stable_features,
temporary_cstring_as_ptr,
@@ -89,8 +97,10 @@
unreachable_patterns,
unreachable_pub,
unsafe_code,
+ unsafe_op_in_unsafe_fn,
unstable_features,
unstable_name_collisions,
+ unsupported_calling_conventions,
unsupported_naked_functions,
unused_allocation,
unused_assignments,
@@ -112,17 +122,13 @@
unused_qualifications,
unused_unsafe,
unused_variables,
- useless_deprecated,
- where_clauses_object_safety,
- while_true
+ useless_deprecated
)]
#![warn(macro_use_extern_crate, unknown_lints)]
#![allow(
bare_trait_objects,
box_pointers,
elided_lifetimes_in_paths,
- invalid_html_tags,
- missing_doc_code_examples,
missing_debug_implementations,
single_use_lifetimes,
unused_results,
diff --git a/duckscript_sdk/Cargo.toml b/duckscript_sdk/Cargo.toml
index 8f2c293..96a6870 100644
--- a/duckscript_sdk/Cargo.toml
+++ b/duckscript_sdk/Cargo.toml
@@ -31,6 +31,7 @@ fs_extra = "^1"
fsio = { version = "^0.2", features = ["temp-path"] }
ftp = "^3"
glob = "^0.3"
+heck = "^0.3"
home = "^0.5"
ignore = "^0.4"
java-properties = "^1"
diff --git a/duckscript_sdk/src/lib.rs b/duckscript_sdk/src/lib.rs
index e27c822..e0fa31e 100755
--- a/duckscript_sdk/src/lib.rs
+++ b/duckscript_sdk/src/lib.rs
@@ -5,8 +5,8 @@
arithmetic_overflow,
array_into_iter,
asm_sub_register,
+ bad_asm_style,
bindings_with_variant_name,
- broken_intra_doc_links,
cenum_impl_drop_cast,
clashing_extern_declarations,
coherence_leak_check,
@@ -18,10 +18,13 @@
dead_code,
deprecated,
deprecated_in_future,
+ deref_nullptr,
drop_bounds,
+ dyn_drop,
ellipsis_inclusive_range_patterns,
explicit_outlives_requirements,
exported_private_dependencies,
+ forbidden_lint_groups,
function_item_references,
ill_formed_attribute_input,
illegal_floating_point_literal_pattern,
@@ -30,18 +33,20 @@
incomplete_features,
incomplete_include,
indirect_structural_match,
+ ineffective_unstable_trait_impl,
inline_no_sanitize,
- invalid_codeblock_attributes,
+ invalid_doc_attributes,
invalid_type_param_default,
invalid_value,
irrefutable_let_patterns,
keyword_idents,
+ large_assignments,
late_bound_lifetime_arguments,
+ legacy_derive_helpers,
macro_expanded_macro_exports_accessed_by_absolute_paths,
meta_variable_misuse,
missing_abi,
missing_copy_implementations,
- missing_crate_level_docs,
missing_docs,
missing_fragment_specifier,
mixed_script_confusables,
@@ -50,26 +55,29 @@
no_mangle_const_items,
no_mangle_generic_items,
non_ascii_idents,
- non_autolinks,
non_camel_case_types,
+ non_fmt_panics,
non_shorthand_field_patterns,
non_snake_case,
non_upper_case_globals,
nontrivial_structural_match,
+ noop_method_call,
order_dependent_trait_objects,
overflowing_literals,
overlapping_range_endpoints,
- panic_fmt,
path_statements,
patterns_in_fns_without_body,
pointer_structural_match,
- private_doc_tests,
private_in_public,
- private_intra_doc_links,
+ proc_macro_back_compat,
proc_macro_derive_resolution_fallback,
pub_use_of_private_extern_crate,
redundant_semicolons,
- safe_packed_borrows,
+ rust_2021_incompatible_closure_captures,
+ rust_2021_incompatible_or_patterns,
+ rust_2021_prefixes_incompatible_syntax,
+ rust_2021_prelude_collisions,
+ semicolon_in_expressions_from_macros,
soft_unstable,
stable_features,
temporary_cstring_as_ptr,
@@ -89,8 +97,10 @@
unreachable_patterns,
unreachable_pub,
unsafe_code,
+ unsafe_op_in_unsafe_fn,
unstable_features,
unstable_name_collisions,
+ unsupported_calling_conventions,
unsupported_naked_functions,
unused_allocation,
unused_assignments,
@@ -112,17 +122,13 @@
unused_qualifications,
unused_unsafe,
unused_variables,
- useless_deprecated,
- where_clauses_object_safety,
- while_true
+ useless_deprecated
)]
#![warn(macro_use_extern_crate, unknown_lints)]
#![allow(
bare_trait_objects,
box_pointers,
elided_lifetimes_in_paths,
- invalid_html_tags,
- missing_doc_code_examples,
missing_debug_implementations,
single_use_lifetimes,
unused_results,
diff --git a/duckscript_sdk/src/sdk/std/string/camelcase/help.md b/duckscript_sdk/src/sdk/std/string/camelcase/help.md
new file mode 100644
index 0000000..b3a2536
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/camelcase/help.md
@@ -0,0 +1,22 @@
+```sh
+var = camelcase text
+```
+
+Converts the provided string into camel case.
+All non-alphanumeric characters are ignored.
+
+#### Parameters
+
+The string to convert.
+
+#### Return Value
+
+The converted string.
+
+#### Examples
+
+```sh
+string = camelcase "hello, world!"
+assert_eq ${string} "HelloWorld"
+```
+
diff --git a/duckscript_sdk/src/sdk/std/string/camelcase/mod.rs b/duckscript_sdk/src/sdk/std/string/camelcase/mod.rs
new file mode 100755
index 0000000..ce65638
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/camelcase/mod.rs
@@ -0,0 +1,44 @@
+use crate::utils::pckg;
+use duckscript::types::command::{Command, CommandResult};
+
+#[cfg(test)]
+#[path = "./mod_test.rs"]
+mod mod_test;
+
+#[derive(Clone)]
+pub(crate) struct CommandImpl {
+ package: String,
+}
+
+impl Command for CommandImpl {
+ fn name(&self) -> String {
+ pckg::concat(&self.package, "CamelCase")
+ }
+
+ fn aliases(&self) -> Vec {
+ vec!["camelcase".to_string()]
+ }
+
+ fn help(&self) -> String {
+ include_str!("help.md").to_string()
+ }
+
+ fn clone_and_box(&self) -> Box {
+ Box::new((*self).clone())
+ }
+
+ fn run(&self, arguments: Vec) -> CommandResult {
+ if arguments.is_empty() {
+ CommandResult::Error("No arguments provided.".to_string())
+ } else {
+ let value = heck::CamelCase::to_camel_case(arguments[0].as_str());
+ CommandResult::Continue(Some(value))
+ }
+ }
+}
+
+pub(crate) fn create(package: &str) -> Box {
+ Box::new(CommandImpl {
+ package: package.to_string(),
+ })
+}
diff --git a/duckscript_sdk/src/sdk/std/string/camelcase/mod_test.rs b/duckscript_sdk/src/sdk/std/string/camelcase/mod_test.rs
new file mode 100644
index 0000000..7e1d33f
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/camelcase/mod_test.rs
@@ -0,0 +1,22 @@
+use super::*;
+use crate::test;
+use crate::test::CommandValidation;
+
+#[test]
+fn common_functions() {
+ test::test_common_command_functions(create(""));
+}
+
+#[test]
+fn run_no_args() {
+ test::run_script_and_error(vec![create("")], "out = camelcase", "out");
+}
+
+#[test]
+fn run_single_argument() {
+ test::run_script_and_validate(
+ vec![create("")],
+ r#"out = camelcase "hello, world!""#,
+ CommandValidation::Match("out".to_string(), "HelloWorld".to_string()),
+ );
+}
diff --git a/duckscript_sdk/src/sdk/std/string/kebabcase/help.md b/duckscript_sdk/src/sdk/std/string/kebabcase/help.md
new file mode 100644
index 0000000..df4a529
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/kebabcase/help.md
@@ -0,0 +1,22 @@
+```sh
+var = kebobcase text
+```
+
+Converts the provided string into kebob case.
+All non-alphanumeric characters are ignored.
+
+#### Parameters
+
+The string to convert.
+
+#### Return Value
+
+The converted string.
+
+#### Examples
+
+```sh
+string = kebobcase "Hello, World!"
+assert_eq ${string} "hello-world"
+```
+
diff --git a/duckscript_sdk/src/sdk/std/string/kebabcase/mod.rs b/duckscript_sdk/src/sdk/std/string/kebabcase/mod.rs
new file mode 100755
index 0000000..db38eb3
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/kebabcase/mod.rs
@@ -0,0 +1,44 @@
+use crate::utils::pckg;
+use duckscript::types::command::{Command, CommandResult};
+
+#[cfg(test)]
+#[path = "./mod_test.rs"]
+mod mod_test;
+
+#[derive(Clone)]
+pub(crate) struct CommandImpl {
+ package: String,
+}
+
+impl Command for CommandImpl {
+ fn name(&self) -> String {
+ pckg::concat(&self.package, "KebabCase")
+ }
+
+ fn aliases(&self) -> Vec {
+ vec!["kebabcase".to_string()]
+ }
+
+ fn help(&self) -> String {
+ include_str!("help.md").to_string()
+ }
+
+ fn clone_and_box(&self) -> Box {
+ Box::new((*self).clone())
+ }
+
+ fn run(&self, arguments: Vec) -> CommandResult {
+ if arguments.is_empty() {
+ CommandResult::Error("No arguments provided.".to_string())
+ } else {
+ let value = heck::KebabCase::to_kebab_case(arguments[0].as_str());
+ CommandResult::Continue(Some(value))
+ }
+ }
+}
+
+pub(crate) fn create(package: &str) -> Box {
+ Box::new(CommandImpl {
+ package: package.to_string(),
+ })
+}
diff --git a/duckscript_sdk/src/sdk/std/string/kebabcase/mod_test.rs b/duckscript_sdk/src/sdk/std/string/kebabcase/mod_test.rs
new file mode 100644
index 0000000..f09e511
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/kebabcase/mod_test.rs
@@ -0,0 +1,22 @@
+use super::*;
+use crate::test;
+use crate::test::CommandValidation;
+
+#[test]
+fn common_functions() {
+ test::test_common_command_functions(create(""));
+}
+
+#[test]
+fn run_no_args() {
+ test::run_script_and_error(vec![create("")], "out = kebabcase", "out");
+}
+
+#[test]
+fn run_single_argument() {
+ test::run_script_and_validate(
+ vec![create("")],
+ r#"out = kebabcase "Hello, World!""#,
+ CommandValidation::Match("out".to_string(), "hello-world".to_string()),
+ );
+}
diff --git a/duckscript_sdk/src/sdk/std/string/lowercase/help.md b/duckscript_sdk/src/sdk/std/string/lowercase/help.md
new file mode 100644
index 0000000..a6a5c85
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/lowercase/help.md
@@ -0,0 +1,21 @@
+```sh
+var = lowercase text
+```
+
+Converts the provided string into lowercase.
+
+#### Parameters
+
+The string to convert.
+
+#### Return Value
+
+The converted string.
+
+#### Examples
+
+```sh
+string = lowercase "Hello World"
+assert_eq ${string} "hello world"
+```
+
diff --git a/duckscript_sdk/src/sdk/std/string/lowercase/mod.rs b/duckscript_sdk/src/sdk/std/string/lowercase/mod.rs
new file mode 100755
index 0000000..2c3283d
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/lowercase/mod.rs
@@ -0,0 +1,44 @@
+use crate::utils::pckg;
+use duckscript::types::command::{Command, CommandResult};
+
+#[cfg(test)]
+#[path = "./mod_test.rs"]
+mod mod_test;
+
+#[derive(Clone)]
+pub(crate) struct CommandImpl {
+ package: String,
+}
+
+impl Command for CommandImpl {
+ fn name(&self) -> String {
+ pckg::concat(&self.package, "Lowercase")
+ }
+
+ fn aliases(&self) -> Vec {
+ vec!["lowercase".to_string()]
+ }
+
+ fn help(&self) -> String {
+ include_str!("help.md").to_string()
+ }
+
+ fn clone_and_box(&self) -> Box {
+ Box::new((*self).clone())
+ }
+
+ fn run(&self, arguments: Vec) -> CommandResult {
+ if arguments.is_empty() {
+ CommandResult::Error("No arguments provided.".to_string())
+ } else {
+ let value = arguments[0].to_lowercase();
+ CommandResult::Continue(Some(value))
+ }
+ }
+}
+
+pub(crate) fn create(package: &str) -> Box {
+ Box::new(CommandImpl {
+ package: package.to_string(),
+ })
+}
diff --git a/duckscript_sdk/src/sdk/std/string/lowercase/mod_test.rs b/duckscript_sdk/src/sdk/std/string/lowercase/mod_test.rs
new file mode 100644
index 0000000..e55fb3d
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/lowercase/mod_test.rs
@@ -0,0 +1,22 @@
+use super::*;
+use crate::test;
+use crate::test::CommandValidation;
+
+#[test]
+fn common_functions() {
+ test::test_common_command_functions(create(""));
+}
+
+#[test]
+fn run_no_args() {
+ test::run_script_and_error(vec![create("")], "out = lowercase", "out");
+}
+
+#[test]
+fn run_single_argument() {
+ test::run_script_and_validate(
+ vec![create("")],
+ r#"out = lowercase "Hello World""#,
+ CommandValidation::Match("out".to_string(), "hello world".to_string()),
+ );
+}
diff --git a/duckscript_sdk/src/sdk/std/string/mod.rs b/duckscript_sdk/src/sdk/std/string/mod.rs
index 3ebe21d..7b38a0c 100755
--- a/duckscript_sdk/src/sdk/std/string/mod.rs
+++ b/duckscript_sdk/src/sdk/std/string/mod.rs
@@ -2,15 +2,19 @@ mod base64;
mod base64_decode;
mod base64_encode;
pub(crate) mod bytes_to_string;
+mod camelcase;
mod concat;
mod contains;
mod ends_with;
pub(crate) mod equals;
mod indexof;
mod is_empty;
+mod kebabcase;
mod last_indexof;
mod length;
+mod lowercase;
mod replace;
+mod snakecase;
mod split;
mod starts_with;
pub(crate) mod string_to_bytes;
@@ -18,6 +22,7 @@ mod substring;
mod trim;
mod trim_end;
mod trim_start;
+mod uppercase;
use crate::utils::pckg;
use duckscript::types::command::Commands;
@@ -32,15 +37,19 @@ pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptEr
commands.set(base64_decode::create(&package))?;
commands.set(base64_encode::create(&package))?;
commands.set(bytes_to_string::create(&package))?;
+ commands.set(camelcase::create(&package))?;
commands.set(concat::create(&package)?)?;
commands.set(contains::create(&package))?;
commands.set(ends_with::create(&package))?;
commands.set(equals::create(&package))?;
commands.set(indexof::create(&package))?;
commands.set(is_empty::create(&package))?;
+ commands.set(kebabcase::create(&package))?;
commands.set(last_indexof::create(&package))?;
commands.set(length::create(&package))?;
+ commands.set(lowercase::create(&package))?;
commands.set(replace::create(&package))?;
+ commands.set(snakecase::create(&package))?;
commands.set(split::create(&package))?;
commands.set(starts_with::create(&package))?;
commands.set(string_to_bytes::create(&package))?;
@@ -48,6 +57,7 @@ pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptEr
commands.set(trim::create(&package))?;
commands.set(trim_start::create(&package))?;
commands.set(trim_end::create(&package))?;
+ commands.set(uppercase::create(&package))?;
Ok(())
}
diff --git a/duckscript_sdk/src/sdk/std/string/snakecase/help.md b/duckscript_sdk/src/sdk/std/string/snakecase/help.md
new file mode 100644
index 0000000..d12c006
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/snakecase/help.md
@@ -0,0 +1,22 @@
+```sh
+var = snakecase text
+```
+
+Converts the provided string into snake case.
+All non-alphanumeric characters are ignored.
+
+#### Parameters
+
+The string to convert.
+
+#### Return Value
+
+The converted string.
+
+#### Examples
+
+```sh
+string = snakecase "Hello, World!"
+assert_eq ${string} "hello_world"
+```
+
diff --git a/duckscript_sdk/src/sdk/std/string/snakecase/mod.rs b/duckscript_sdk/src/sdk/std/string/snakecase/mod.rs
new file mode 100755
index 0000000..2f31d4e
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/snakecase/mod.rs
@@ -0,0 +1,44 @@
+use crate::utils::pckg;
+use duckscript::types::command::{Command, CommandResult};
+
+#[cfg(test)]
+#[path = "./mod_test.rs"]
+mod mod_test;
+
+#[derive(Clone)]
+pub(crate) struct CommandImpl {
+ package: String,
+}
+
+impl Command for CommandImpl {
+ fn name(&self) -> String {
+ pckg::concat(&self.package, "SnakeCase")
+ }
+
+ fn aliases(&self) -> Vec {
+ vec!["snakecase".to_string()]
+ }
+
+ fn help(&self) -> String {
+ include_str!("help.md").to_string()
+ }
+
+ fn clone_and_box(&self) -> Box {
+ Box::new((*self).clone())
+ }
+
+ fn run(&self, arguments: Vec) -> CommandResult {
+ if arguments.is_empty() {
+ CommandResult::Error("No arguments provided.".to_string())
+ } else {
+ let value = heck::SnakeCase::to_snake_case(arguments[0].as_str());
+ CommandResult::Continue(Some(value))
+ }
+ }
+}
+
+pub(crate) fn create(package: &str) -> Box {
+ Box::new(CommandImpl {
+ package: package.to_string(),
+ })
+}
diff --git a/duckscript_sdk/src/sdk/std/string/snakecase/mod_test.rs b/duckscript_sdk/src/sdk/std/string/snakecase/mod_test.rs
new file mode 100644
index 0000000..0bcfaa9
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/snakecase/mod_test.rs
@@ -0,0 +1,22 @@
+use super::*;
+use crate::test;
+use crate::test::CommandValidation;
+
+#[test]
+fn common_functions() {
+ test::test_common_command_functions(create(""));
+}
+
+#[test]
+fn run_no_args() {
+ test::run_script_and_error(vec![create("")], "out = snakecase", "out");
+}
+
+#[test]
+fn run_single_argument() {
+ test::run_script_and_validate(
+ vec![create("")],
+ r#"out = snakecase "Hello, World!""#,
+ CommandValidation::Match("out".to_string(), "hello_world".to_string()),
+ );
+}
diff --git a/duckscript_sdk/src/sdk/std/string/uppercase/help.md b/duckscript_sdk/src/sdk/std/string/uppercase/help.md
new file mode 100644
index 0000000..f261545
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/uppercase/help.md
@@ -0,0 +1,21 @@
+```sh
+var = uppercase text
+```
+
+Converts the provided string into uppercase.
+
+#### Parameters
+
+The string to convert.
+
+#### Return Value
+
+The converted string.
+
+#### Examples
+
+```sh
+string = uppercase "Hello World"
+assert_eq ${string} "HELLO WORLD"
+```
+
diff --git a/duckscript_sdk/src/sdk/std/string/uppercase/mod.rs b/duckscript_sdk/src/sdk/std/string/uppercase/mod.rs
new file mode 100755
index 0000000..11d2a2f
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/uppercase/mod.rs
@@ -0,0 +1,44 @@
+use crate::utils::pckg;
+use duckscript::types::command::{Command, CommandResult};
+
+#[cfg(test)]
+#[path = "./mod_test.rs"]
+mod mod_test;
+
+#[derive(Clone)]
+pub(crate) struct CommandImpl {
+ package: String,
+}
+
+impl Command for CommandImpl {
+ fn name(&self) -> String {
+ pckg::concat(&self.package, "Uppercase")
+ }
+
+ fn aliases(&self) -> Vec {
+ vec!["uppercase".to_string()]
+ }
+
+ fn help(&self) -> String {
+ include_str!("help.md").to_string()
+ }
+
+ fn clone_and_box(&self) -> Box {
+ Box::new((*self).clone())
+ }
+
+ fn run(&self, arguments: Vec) -> CommandResult {
+ if arguments.is_empty() {
+ CommandResult::Error("No arguments provided.".to_string())
+ } else {
+ let value = arguments[0].to_uppercase();
+ CommandResult::Continue(Some(value))
+ }
+ }
+}
+
+pub(crate) fn create(package: &str) -> Box {
+ Box::new(CommandImpl {
+ package: package.to_string(),
+ })
+}
diff --git a/duckscript_sdk/src/sdk/std/string/uppercase/mod_test.rs b/duckscript_sdk/src/sdk/std/string/uppercase/mod_test.rs
new file mode 100644
index 0000000..bfd6905
--- /dev/null
+++ b/duckscript_sdk/src/sdk/std/string/uppercase/mod_test.rs
@@ -0,0 +1,22 @@
+use super::*;
+use crate::test;
+use crate::test::CommandValidation;
+
+#[test]
+fn common_functions() {
+ test::test_common_command_functions(create(""));
+}
+
+#[test]
+fn run_no_args() {
+ test::run_script_and_error(vec![create("")], "out = uppercase", "out");
+}
+
+#[test]
+fn run_single_argument() {
+ test::run_script_and_validate(
+ vec![create("")],
+ r#"out = uppercase "hello world""#,
+ CommandValidation::Match("out".to_string(), "HELLO WORLD".to_string()),
+ );
+}
diff --git a/duckscript_sdk/src/test/mod.rs b/duckscript_sdk/src/test/mod.rs
index c3162bd..dde918e 100644
--- a/duckscript_sdk/src/test/mod.rs
+++ b/duckscript_sdk/src/test/mod.rs
@@ -244,7 +244,7 @@ pub(crate) fn run_script_and_error(
context
}
- Err(error) => panic!(error.to_string()),
+ Err(error) => panic!("{}", error.to_string()),
}
}
@@ -313,7 +313,7 @@ pub(crate) fn run_script_and_validate(
context
}
- Err(error) => panic!(error.to_string()),
+ Err(error) => panic!("{}", error.to_string()),
}
}
diff --git a/test/std/string/camelcase_test.ds b/test/std/string/camelcase_test.ds
new file mode 100644
index 0000000..f350fc9
--- /dev/null
+++ b/test/std/string/camelcase_test.ds
@@ -0,0 +1,12 @@
+
+fn test_without_symbols
+ output = camelcase "Hello world 22"
+
+ assert_eq ${output} "HelloWorld22"
+end
+
+fn test_with_symbols
+ output = camelcase "Hello!@#$% world^&*()[]{}22"
+
+ assert_eq ${output} "HelloWorld22"
+end
diff --git a/test/std/string/kebabcase_test.ds b/test/std/string/kebabcase_test.ds
new file mode 100644
index 0000000..efde724
--- /dev/null
+++ b/test/std/string/kebabcase_test.ds
@@ -0,0 +1,12 @@
+
+fn test_without_symbols
+ output = kebabcase "Hello World 22"
+
+ assert_eq ${output} "hello-world-22"
+end
+
+fn test_with_symbols
+ output = kebabcase "hello!@#$% world^&*()[]{}22"
+
+ assert_eq ${output} "hello-world-22"
+end
diff --git a/test/std/string/lowercase_test.ds b/test/std/string/lowercase_test.ds
new file mode 100644
index 0000000..f1521cf
--- /dev/null
+++ b/test/std/string/lowercase_test.ds
@@ -0,0 +1,6 @@
+
+fn test_conversion
+ output = lowercase "Hello World"
+
+ assert_eq ${output} "hello world"
+end
diff --git a/test/std/string/snakecase_test.ds b/test/std/string/snakecase_test.ds
new file mode 100644
index 0000000..19e6ef7
--- /dev/null
+++ b/test/std/string/snakecase_test.ds
@@ -0,0 +1,12 @@
+
+fn test_without_symbols
+ output = snakecase "Hello world 22"
+
+ assert_eq ${output} "hello_world_22"
+end
+
+fn test_with_symbols
+ output = snakecase "Hello!@#$% world^&*()[]{}22"
+
+ assert_eq ${output} "hello_world_22"
+end
diff --git a/test/std/string/uppercase_test.ds b/test/std/string/uppercase_test.ds
new file mode 100644
index 0000000..da6b65f
--- /dev/null
+++ b/test/std/string/uppercase_test.ds
@@ -0,0 +1,6 @@
+
+fn test_conversion
+ output = uppercase "Hello World"
+
+ assert_eq ${output} "HELLO WORLD"
+end