Version 0.5.1

This commit is contained in:
Filip Tibell 2023-02-25 13:41:50 +01:00
parent c83917206f
commit 7d75d5c52f
No known key found for this signature in database
9 changed files with 313 additions and 41 deletions

View file

@ -8,6 +8,37 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## `0.5.1` - February 25th, 2023
### Added
- Added `net.encode` and `net.decode` which are equivalent to `net.jsonEncode` and `net.jsonDecode`, but with support for more formats.
**_WARNING: Unstable API_**
_This API is unstable and may change or be removed in the next major version of Lune. The purpose of making a new release with these functions is to gather feedback from the community, and potentially replace the JSON-specific encoding and decoding utilities._
Example usage:
```lua
local toml = net.decode("toml", [[
[package]
name = "my-cool-toml-package"
version = "0.1.0"
[values]
epic = true
]])
assert(toml.package.name == "my-cool-toml-package")
assert(toml.package.version == "0.1.0")
assert(toml.values.epic == true)
```
### Fixed
- Fixed indentation of closing curly bracket when printing tables
## `0.5.0` - February 23rd, 2023 ## `0.5.0` - February 23rd, 2023
### Added ### Added

54
Cargo.lock generated
View file

@ -797,6 +797,7 @@ dependencies = [
"serde_yaml", "serde_yaml",
"tokio", "tokio",
"tokio-tungstenite", "tokio-tungstenite",
"toml",
] ]
[[package]] [[package]]
@ -1276,6 +1277,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_spanned"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "serde_urlencoded" name = "serde_urlencoded"
version = "0.7.1" version = "0.7.1"
@ -1510,6 +1520,41 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "toml"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a1eb0622d28f4b9c90adc4ea4b2b46b47663fde9ac5fafcb14a1369d5508825"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]] [[package]]
name = "tower-service" name = "tower-service"
version = "0.3.2" version = "0.3.2"
@ -1858,6 +1903,15 @@ version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "winnow"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c06e7dbfe731192c512aa707249279d720876a868eb08f21ea93eb9de1eca9"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "winreg" name = "winreg"
version = "0.10.1" version = "0.10.1"

View file

@ -2,6 +2,8 @@
members = ["packages/cli", "packages/lib"] members = ["packages/cli", "packages/lib"]
default-members = ["packages/cli"] default-members = ["packages/cli"]
# Package config values shared across all packages,
# such as version, license, and other metadata
[workspace.package] [workspace.package]
version = "0.5.0" version = "0.5.0"
edition = "2021" edition = "2021"
@ -12,23 +14,32 @@ readme = "README.md"
keywords = ["cli", "lua", "luau", "scripts"] keywords = ["cli", "lua", "luau", "scripts"]
categories = ["command-line-interface"] categories = ["command-line-interface"]
# Shared dependencies that are used across 2 or more packages
# These are declared here to ensure consistent versioning
[workspace.dependencies] [workspace.dependencies]
console = "0.15" console = "0.15"
futures-util = "0.3" futures-util = "0.3"
lazy_static = "1.4" lazy_static = "1.4"
# Serde dependencies, supporting user-facing formats: json, yaml, toml
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["preserve_order"] } serde_json = { version = "1.0", features = ["preserve_order"] }
serde_yaml = "0.9" serde_yaml = "0.9"
toml = { version = "0.7", features = ["preserve_order"] }
# Tokio runtime & async clients
tokio = { version = "1.24", features = ["full"] } tokio = { version = "1.24", features = ["full"] }
reqwest = { version = "0.11", default-features = false, features = [
"rustls-tls",
] }
[workspace.dependencies.reqwest] # Profile for building the release binary, with the following options set:
version = "0.11" # 1. Optimize for size
default-features = false # 2. Automatically strip symbols from the binary
features = ["rustls-tls"] # 3. Enable link-time optimization
# 4. Remove extra panic info
[profile.release] [profile.release]
strip = true # Automatically strip symbols from the binary. opt-level = "z"
opt-level = "z" # Optimize for size. strip = true
lto = true # Enable link-time optimization lto = true
panic = "abort" # Remove extra panic info panic = "abort"

View file

@ -162,6 +162,8 @@ declare fs: {
type NetMethod = "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "PATCH" type NetMethod = "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "PATCH"
type NetEncodeDecodeFormat = "json" | "yaml" | "toml"
--[=[ --[=[
@type NetFetchParams @type NetFetchParams
@within Net @within Net
@ -364,6 +366,37 @@ declare net: {
@return The decoded lua value @return The decoded lua value
]=] ]=]
jsonDecode: (encoded: string) -> any, jsonDecode: (encoded: string) -> any,
--[=[
@within Net
@must_use
***WARNING:** Unstable API*
*This API is unstable and may change or be removed in the next major version of Lune.*
Encodes the given value using the given format.
@param format The format to use
@param value The value to encode
@param pretty If the encoded string should be human-readable, including things such as newlines and spaces. Only supported for json and toml formats, and defaults to false
@return The encoded string
]=]
encode: (format: NetEncodeDecodeFormat, value: any, pretty: boolean?) -> string,
--[=[
@within Net
@must_use
***WARNING:** Unstable API*
*This API is unstable and may change or be removed in the next major version of Lune.*
Decodes the given string using the given format into a lua value.
@param format The format to use
@param encoded The JSON string to decode
@return The decoded lua value
]=]
decode: (format: NetEncodeDecodeFormat, encoded: string) -> any,
} }
type ProcessSpawnOptionsStdio = "inherit" | "default" type ProcessSpawnOptionsStdio = "inherit" | "default"

View file

@ -21,6 +21,7 @@ lazy_static.workspace = true
serde.workspace = true serde.workspace = true
serde_json.workspace = true serde_json.workspace = true
serde_yaml.workspace = true serde_yaml.workspace = true
toml.workspace = true
tokio.workspace = true tokio.workspace = true
reqwest.workspace = true reqwest.workspace = true

View file

@ -8,8 +8,8 @@ use tokio::{sync::mpsc, task};
use crate::lua::{ use crate::lua::{
net::{ net::{
NetClient, NetClientBuilder, NetLocalExec, NetService, NetWebSocket, RequestConfig, EncodeDecodeConfig, EncodeDecodeFormat, NetClient, NetClientBuilder, NetLocalExec,
ServeConfig, NetService, NetWebSocket, RequestConfig, ServeConfig,
}, },
table::TableBuilder, table::TableBuilder,
task::{TaskScheduler, TaskSchedulerAsyncExt}, task::{TaskScheduler, TaskSchedulerAsyncExt},
@ -25,6 +25,8 @@ pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
lua.set_named_registry_value("net.client", client)?; lua.set_named_registry_value("net.client", client)?;
// Create the global table for net // Create the global table for net
TableBuilder::new(lua)? TableBuilder::new(lua)?
.with_function("encode", net_encode)?
.with_function("decode", net_decode)?
.with_function("jsonEncode", net_json_encode)? .with_function("jsonEncode", net_json_encode)?
.with_function("jsonDecode", net_json_decode)? .with_function("jsonDecode", net_json_decode)?
.with_async_function("request", net_request)? .with_async_function("request", net_request)?
@ -42,17 +44,32 @@ fn create_user_agent_header() -> String {
format!("{github_owner}-{github_repo}-cli") format!("{github_owner}-{github_repo}-cli")
} }
fn net_json_encode(_: &'static Lua, (val, pretty): (LuaValue, Option<bool>)) -> LuaResult<String> { fn net_encode<'a>(
if let Some(true) = pretty { lua: &'static Lua,
serde_json::to_string_pretty(&val).map_err(LuaError::external) (format, val, pretty): (EncodeDecodeFormat, LuaValue<'a>, Option<bool>),
} else { ) -> LuaResult<LuaString<'a>> {
serde_json::to_string(&val).map_err(LuaError::external) let config = EncodeDecodeConfig::from((format, pretty.unwrap_or_default()));
} config.serialize_to_string(lua, val)
} }
fn net_json_decode(lua: &'static Lua, json: String) -> LuaResult<LuaValue> { fn net_decode<'a>(
let json: serde_json::Value = serde_json::from_str(&json).map_err(LuaError::external)?; lua: &'static Lua,
lua.to_value(&json) (format, str): (EncodeDecodeFormat, LuaString<'a>),
) -> LuaResult<LuaValue<'a>> {
let config = EncodeDecodeConfig::from(format);
config.deserialize_from_string(lua, str)
}
fn net_json_encode<'a>(
lua: &'static Lua,
(val, pretty): (LuaValue<'a>, Option<bool>),
) -> LuaResult<LuaString<'a>> {
EncodeDecodeConfig::from((EncodeDecodeFormat::Json, pretty.unwrap_or_default()))
.serialize_to_string(lua, val)
}
fn net_json_decode<'a>(lua: &'static Lua, json: LuaString<'a>) -> LuaResult<LuaValue<'a>> {
EncodeDecodeConfig::from(EncodeDecodeFormat::Json).deserialize_from_string(lua, json)
} }
async fn net_request<'a>(lua: &'static Lua, config: RequestConfig<'a>) -> LuaResult<LuaTable<'a>> { async fn net_request<'a>(lua: &'static Lua, config: RequestConfig<'a>) -> LuaResult<LuaTable<'a>> {

View file

@ -1,9 +1,11 @@
mod client; mod client;
mod config; mod config;
mod response; mod response;
mod serde;
mod server; mod server;
mod websocket; mod websocket;
pub use self::serde::{EncodeDecodeConfig, EncodeDecodeFormat};
pub use client::{NetClient, NetClientBuilder}; pub use client::{NetClient, NetClientBuilder};
pub use config::{RequestConfig, ServeConfig}; pub use config::{RequestConfig, ServeConfig};
pub use response::{NetServeResponse, NetServeResponseKind}; pub use response::{NetServeResponse, NetServeResponseKind};

View file

@ -0,0 +1,123 @@
use mlua::prelude::*;
use serde_json::Value as JsonValue;
use serde_yaml::Value as YamlValue;
use toml::Value as TomlValue;
// Serde config
#[derive(Debug, Clone, Copy)]
pub enum EncodeDecodeFormat {
Json,
Yaml,
Toml,
}
impl<'lua> FromLua<'lua> for EncodeDecodeFormat {
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<Self> {
if let LuaValue::String(s) = &value {
match s.to_string_lossy().to_ascii_lowercase().trim() {
"json" => Ok(Self::Json),
"yaml" => Ok(Self::Yaml),
"toml" => Ok(Self::Toml),
kind => Err(LuaError::FromLuaConversionError {
from: value.type_name(),
to: "EncodeDecodeFormat",
message: Some(format!(
"Invalid format '{kind}', valid formats are: json, yaml, toml"
)),
}),
}
} else {
Err(LuaError::FromLuaConversionError {
from: value.type_name(),
to: "EncodeDecodeFormat",
message: None,
})
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct EncodeDecodeConfig {
pub format: EncodeDecodeFormat,
pub pretty: bool,
}
impl EncodeDecodeConfig {
pub fn serialize_to_string<'lua>(
self,
lua: &'lua Lua,
value: LuaValue<'lua>,
) -> LuaResult<LuaString<'lua>> {
let bytes = match self.format {
EncodeDecodeFormat::Json => {
if self.pretty {
serde_json::to_vec_pretty(&value).map_err(LuaError::external)?
} else {
serde_json::to_vec(&value).map_err(LuaError::external)?
}
}
EncodeDecodeFormat::Yaml => {
let mut writer = Vec::with_capacity(128);
serde_yaml::to_writer(&mut writer, &value).map_err(LuaError::external)?;
writer
}
EncodeDecodeFormat::Toml => {
let s = if self.pretty {
toml::to_string_pretty(&value).map_err(LuaError::external)?
} else {
toml::to_string(&value).map_err(LuaError::external)?
};
s.as_bytes().to_vec()
}
};
lua.create_string(&bytes)
}
pub fn deserialize_from_string<'lua>(
self,
lua: &'lua Lua,
string: LuaString<'lua>,
) -> LuaResult<LuaValue<'lua>> {
let bytes = string.as_bytes();
match self.format {
EncodeDecodeFormat::Json => {
let value: JsonValue = serde_json::from_slice(bytes).map_err(LuaError::external)?;
lua.to_value(&value)
}
EncodeDecodeFormat::Yaml => {
let value: YamlValue = serde_yaml::from_slice(bytes).map_err(LuaError::external)?;
lua.to_value(&value)
}
EncodeDecodeFormat::Toml => {
if let Ok(s) = string.to_str() {
let value: TomlValue = toml::from_str(s).map_err(LuaError::external)?;
lua.to_value(&value)
} else {
Err(LuaError::RuntimeError(
"TOML must be valid utf-8".to_string(),
))
}
}
}
}
}
impl From<EncodeDecodeFormat> for EncodeDecodeConfig {
fn from(format: EncodeDecodeFormat) -> Self {
Self {
format,
pretty: false,
}
}
}
impl From<(EncodeDecodeFormat, bool)> for EncodeDecodeConfig {
fn from(value: (EncodeDecodeFormat, bool)) -> Self {
Self {
format: value.0,
pretty: value.1,
}
}
}

View file

@ -156,7 +156,7 @@ pub fn pretty_format_value(
if is_empty { if is_empty {
write!(buffer, "{}", STYLE_DIM.apply_to(" }"))?; write!(buffer, "{}", STYLE_DIM.apply_to(" }"))?;
} else { } else {
write!(buffer, "\n{}", STYLE_DIM.apply_to("}"))?; write!(buffer, "\n{depth_indent}{}", STYLE_DIM.apply_to("}"))?;
} }
} }
} }