mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 13:00:37 +00:00
Version 0.5.1
This commit is contained in:
parent
c83917206f
commit
7d75d5c52f
9 changed files with 313 additions and 41 deletions
31
CHANGELOG.md
31
CHANGELOG.md
|
@ -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/),
|
||||
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
|
||||
|
||||
### Added
|
||||
|
|
54
Cargo.lock
generated
54
Cargo.lock
generated
|
@ -797,6 +797,7 @@ dependencies = [
|
|||
"serde_yaml",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1276,6 +1277,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
|
@ -1510,6 +1520,41 @@ dependencies = [
|
|||
"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]]
|
||||
name = "tower-service"
|
||||
version = "0.3.2"
|
||||
|
@ -1858,6 +1903,15 @@ version = "0.42.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c06e7dbfe731192c512aa707249279d720876a868eb08f21ea93eb9de1eca9"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
|
|
29
Cargo.toml
29
Cargo.toml
|
@ -2,6 +2,8 @@
|
|||
members = ["packages/cli", "packages/lib"]
|
||||
default-members = ["packages/cli"]
|
||||
|
||||
# Package config values shared across all packages,
|
||||
# such as version, license, and other metadata
|
||||
[workspace.package]
|
||||
version = "0.5.0"
|
||||
edition = "2021"
|
||||
|
@ -12,23 +14,32 @@ readme = "README.md"
|
|||
keywords = ["cli", "lua", "luau", "scripts"]
|
||||
categories = ["command-line-interface"]
|
||||
|
||||
# Shared dependencies that are used across 2 or more packages
|
||||
# These are declared here to ensure consistent versioning
|
||||
[workspace.dependencies]
|
||||
console = "0.15"
|
||||
futures-util = "0.3"
|
||||
lazy_static = "1.4"
|
||||
|
||||
# Serde dependencies, supporting user-facing formats: json, yaml, toml
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||
serde_yaml = "0.9"
|
||||
toml = { version = "0.7", features = ["preserve_order"] }
|
||||
|
||||
# Tokio runtime & async clients
|
||||
tokio = { version = "1.24", features = ["full"] }
|
||||
reqwest = { version = "0.11", default-features = false, features = [
|
||||
"rustls-tls",
|
||||
] }
|
||||
|
||||
[workspace.dependencies.reqwest]
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
features = ["rustls-tls"]
|
||||
|
||||
# Profile for building the release binary, with the following options set:
|
||||
# 1. Optimize for size
|
||||
# 2. Automatically strip symbols from the binary
|
||||
# 3. Enable link-time optimization
|
||||
# 4. Remove extra panic info
|
||||
[profile.release]
|
||||
strip = true # Automatically strip symbols from the binary.
|
||||
opt-level = "z" # Optimize for size.
|
||||
lto = true # Enable link-time optimization
|
||||
panic = "abort" # Remove extra panic info
|
||||
opt-level = "z"
|
||||
strip = true
|
||||
lto = true
|
||||
panic = "abort"
|
||||
|
|
|
@ -162,6 +162,8 @@ declare fs: {
|
|||
|
||||
type NetMethod = "GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "PATCH"
|
||||
|
||||
type NetEncodeDecodeFormat = "json" | "yaml" | "toml"
|
||||
|
||||
--[=[
|
||||
@type NetFetchParams
|
||||
@within Net
|
||||
|
@ -364,6 +366,37 @@ declare net: {
|
|||
@return The decoded lua value
|
||||
]=]
|
||||
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"
|
||||
|
|
|
@ -21,6 +21,7 @@ lazy_static.workspace = true
|
|||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde_yaml.workspace = true
|
||||
toml.workspace = true
|
||||
tokio.workspace = true
|
||||
reqwest.workspace = true
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ use tokio::{sync::mpsc, task};
|
|||
|
||||
use crate::lua::{
|
||||
net::{
|
||||
NetClient, NetClientBuilder, NetLocalExec, NetService, NetWebSocket, RequestConfig,
|
||||
ServeConfig,
|
||||
EncodeDecodeConfig, EncodeDecodeFormat, NetClient, NetClientBuilder, NetLocalExec,
|
||||
NetService, NetWebSocket, RequestConfig, ServeConfig,
|
||||
},
|
||||
table::TableBuilder,
|
||||
task::{TaskScheduler, TaskSchedulerAsyncExt},
|
||||
|
@ -25,6 +25,8 @@ pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
|
|||
lua.set_named_registry_value("net.client", client)?;
|
||||
// Create the global table for net
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("encode", net_encode)?
|
||||
.with_function("decode", net_decode)?
|
||||
.with_function("jsonEncode", net_json_encode)?
|
||||
.with_function("jsonDecode", net_json_decode)?
|
||||
.with_async_function("request", net_request)?
|
||||
|
@ -42,17 +44,32 @@ fn create_user_agent_header() -> String {
|
|||
format!("{github_owner}-{github_repo}-cli")
|
||||
}
|
||||
|
||||
fn net_json_encode(_: &'static Lua, (val, pretty): (LuaValue, Option<bool>)) -> LuaResult<String> {
|
||||
if let Some(true) = pretty {
|
||||
serde_json::to_string_pretty(&val).map_err(LuaError::external)
|
||||
} else {
|
||||
serde_json::to_string(&val).map_err(LuaError::external)
|
||||
}
|
||||
fn net_encode<'a>(
|
||||
lua: &'static Lua,
|
||||
(format, val, pretty): (EncodeDecodeFormat, LuaValue<'a>, Option<bool>),
|
||||
) -> LuaResult<LuaString<'a>> {
|
||||
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> {
|
||||
let json: serde_json::Value = serde_json::from_str(&json).map_err(LuaError::external)?;
|
||||
lua.to_value(&json)
|
||||
fn net_decode<'a>(
|
||||
lua: &'static Lua,
|
||||
(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>> {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
mod client;
|
||||
mod config;
|
||||
mod response;
|
||||
mod serde;
|
||||
mod server;
|
||||
mod websocket;
|
||||
|
||||
pub use self::serde::{EncodeDecodeConfig, EncodeDecodeFormat};
|
||||
pub use client::{NetClient, NetClientBuilder};
|
||||
pub use config::{RequestConfig, ServeConfig};
|
||||
pub use response::{NetServeResponse, NetServeResponseKind};
|
||||
|
|
123
packages/lib/src/lua/net/serde.rs
Normal file
123
packages/lib/src/lua/net/serde.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -156,7 +156,7 @@ pub fn pretty_format_value(
|
|||
if is_empty {
|
||||
write!(buffer, "{}", STYLE_DIM.apply_to(" }"))?;
|
||||
} else {
|
||||
write!(buffer, "\n{}", STYLE_DIM.apply_to("}"))?;
|
||||
write!(buffer, "\n{depth_indent}{}", STYLE_DIM.apply_to("}"))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue