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

@ -14,7 +14,7 @@ export type FsWriteOptions = {
--[=[ --[=[
@class FS @class FS
Filesystem Filesystem
]=] ]=]
declare fs: { declare fs: {
@ -40,7 +40,7 @@ declare fs: {
@must_use @must_use
Reads entries in a directory at `path`. Reads entries in a directory at `path`.
An error will be thrown in the following situations: An error will be thrown in the following situations:
* `path` does not point to an existing directory. * `path` does not point to an existing directory.
@ -146,9 +146,9 @@ declare fs: {
Throws an error if a file or directory already exists at the target path. Throws an error if a file or directory already exists at the target path.
This can be bypassed by passing `true` as the third argument, or a dictionary of options. This can be bypassed by passing `true` as the third argument, or a dictionary of options.
Refer to the documentation for `FsWriteOptions` for specific option keys and their values. Refer to the documentation for `FsWriteOptions` for specific option keys and their values.
An error will be thrown in the following situations: An error will be thrown in the following situations:
* The current process lacks permissions to read at `from` or write at `to`. * The current process lacks permissions to read at `from` or write at `to`.
* The new path exists on a different mount point. * The new path exists on a different mount point.
* Some other I/O error occurred. * Some other I/O error occurred.
@ -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
@ -231,7 +233,7 @@ export type NetRequest = {
--[=[ --[=[
@type NetRequest @type NetRequest
@within Net @within Net
Response type for requests in `net.serve`. Response type for requests in `net.serve`.
This is a dictionary that may contain one or more of the following values: This is a dictionary that may contain one or more of the following values:
@ -280,7 +282,7 @@ export type NetServeHandle = {
@within Net @within Net
A reference to a web socket connection. A reference to a web socket connection.
The web socket may be in either an "open" or a "closed" state, changing its current behavior. The web socket may be in either an "open" or a "closed" state, changing its current behavior.
When open: When open:
@ -311,7 +313,7 @@ declare net: {
@within Net @within Net
Sends an HTTP request using the given url and / or parameters, and returns a dictionary that describes the response received. Sends an HTTP request using the given url and / or parameters, and returns a dictionary that describes the response received.
Only throws an error if a miscellaneous network or I/O error occurs, never for unsuccessful status codes. Only throws an error if a miscellaneous network or I/O error occurs, never for unsuccessful status codes.
@param config The URL or request config to use @param config The URL or request config to use
@ -323,7 +325,7 @@ declare net: {
@must_use @must_use
Connects to a web socket at the given URL. Connects to a web socket at the given URL.
Throws an error if the server at the given URL does not support Throws an error if the server at the given URL does not support
web sockets, or if a miscellaneous network or I/O error occurs. web sockets, or if a miscellaneous network or I/O error occurs.
@ -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"
@ -415,9 +448,9 @@ declare process: {
--[=[ --[=[
@within Process @within Process
@read_only @read_only
The current operating system being used. The current operating system being used.
Possible values: Possible values:
* `"linux"` * `"linux"`
@ -428,9 +461,9 @@ declare process: {
--[=[ --[=[
@within Process @within Process
@read_only @read_only
The architecture of the processor currently being used. The architecture of the processor currently being used.
Possible values: Possible values:
* `"x86_64"` * `"x86_64"`
@ -468,13 +501,13 @@ declare process: {
Exit code 0 is treated as a successful exit, any other value is treated as an error. Exit code 0 is treated as a successful exit, any other value is treated as an error.
Setting the exit code using this function will override any otherwise automatic exit code. Setting the exit code using this function will override any otherwise automatic exit code.
@param code The exit code to set @param code The exit code to set
]=] ]=]
exit: (code: number?) -> (), exit: (code: number?) -> (),
--[=[ --[=[
@within Process @within Process
Spawns a child process that will run the program `program`, and returns a dictionary that describes the final status and ouput of the child process. Spawns a child process that will run the program `program`, and returns a dictionary that describes the final status and ouput of the child process.
The second argument, `params`, can be passed as a list of string parameters to give to the program. The second argument, `params`, can be passed as a list of string parameters to give to the program.
@ -497,7 +530,7 @@ declare process: {
--[=[ --[=[
@class Stdio @class Stdio
Standard input / output & utility functions Standard input / output & utility functions
]=] ]=]
declare stdio: { declare stdio: {
--[=[ --[=[
@ -507,9 +540,9 @@ declare stdio: {
Return an ANSI string that can be used to modify the persistent output color. Return an ANSI string that can be used to modify the persistent output color.
Pass `"reset"` to get a string that can reset the persistent output color. Pass `"reset"` to get a string that can reset the persistent output color.
### Example usage ### Example usage
```lua ```lua
stdio.write(stdio.color("red")) stdio.write(stdio.color("red"))
print("This text will be red") print("This text will be red")
@ -528,9 +561,9 @@ declare stdio: {
Return an ANSI string that can be used to modify the persistent output style. Return an ANSI string that can be used to modify the persistent output style.
Pass `"reset"` to get a string that can reset the persistent output style. Pass `"reset"` to get a string that can reset the persistent output style.
### Example usage ### Example usage
```lua ```lua
stdio.write(stdio.style("bold")) stdio.write(stdio.style("bold"))
print("This text will be bold") print("This text will be bold")
@ -629,7 +662,7 @@ declare task: {
@within Task @within Task
Instantly runs a thread or function. Instantly runs a thread or function.
If the spawned task yields, the thread that spawned the task If the spawned task yields, the thread that spawned the task
will resume, letting the spawned task run in the background. will resume, letting the spawned task run in the background.

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("}"))?;
} }
} }
} }