mirror of
https://github.com/pesde-pkg/tooling.git
synced 2025-01-07 15:09:09 +00:00
refactor(lib): use extension pattern for result<->option
Formerly, we used metatables to get custom `Option` and `Result` objects which were difficult to type properly, leading to a lot of `unknown` and `any` casts. This refactor fixes it by making extensions opt-in, where we import the extension methods separately from the original implementations, thereby allowing us to not have to typecast things everywhere.
This commit is contained in:
parent
45627ea4a9
commit
ead60c003e
15 changed files with 96 additions and 86 deletions
|
@ -7,11 +7,11 @@ local pathfs = require("../lune_packages/pathfs")
|
|||
local base64 = require("../lune_packages/base64")
|
||||
|
||||
local manifestTypes = require("../toolchainlib/src/manifest")
|
||||
local types = require("../toolchainlib/src/utils/result_option_conv")
|
||||
local Option = types.Option
|
||||
type Option<T> = types.Option<T>
|
||||
local Result = types.Result
|
||||
type Result<T, E> = types.Result<T, E>
|
||||
local Result = require("../lune_packages/result")
|
||||
local Option = require("../lune_packages/option")
|
||||
type Result<T, E> = Result.Result<T, E>
|
||||
type Option<T> = Option.Option<T>
|
||||
|
||||
local Github = require("../toolchainlib/src/github")
|
||||
|
||||
type GithubContents = {
|
||||
|
|
18
pesde.lock
18
pesde.lock
|
@ -65,6 +65,24 @@ index_url = "https://github.com/daimond113/pesde-index"
|
|||
environment = "lune"
|
||||
lib = "lib/init.luau"
|
||||
|
||||
[graph."lukadev_0/result"."1.2.0 lune"]
|
||||
direct = ["result", { name = "lukadev_0/result", version = "^1.2.0" }, "dev"]
|
||||
resolved_ty = "dev"
|
||||
|
||||
[graph."lukadev_0/result"."1.2.0 lune".target]
|
||||
environment = "lune"
|
||||
lib = "lib/init.luau"
|
||||
|
||||
[graph."lukadev_0/result"."1.2.0 lune".pkg_ref]
|
||||
ref_ty = "pesde"
|
||||
name = "lukadev_0/result"
|
||||
version = "1.2.0"
|
||||
index_url = "https://github.com/daimond113/pesde-index"
|
||||
|
||||
[graph."lukadev_0/result"."1.2.0 lune".pkg_ref.target]
|
||||
environment = "lune"
|
||||
lib = "lib/init.luau"
|
||||
|
||||
[graph."synpixel/base64"."3.0.1 lune"]
|
||||
direct = ["base64", { name = "synpixel/base64", version = "^3.0.1" }, "dev"]
|
||||
resolved_ty = "dev"
|
||||
|
|
|
@ -9,6 +9,7 @@ environment = "lune"
|
|||
|
||||
[dev_dependencies]
|
||||
option = { name = "lukadev_0/option", version = "^1.2.0" }
|
||||
result = { name = "lukadev_0/result", version = "^1.2.0" }
|
||||
pathfs = { name = "jiwonz/pathfs", version = "^0.1.0" }
|
||||
base64 = { name = "synpixel/base64", version = "^3.0.1" }
|
||||
|
||||
|
|
|
@ -4,13 +4,13 @@ local process = require("@lune/process")
|
|||
local dirs = require("../lune_packages/dirs")
|
||||
local pathfs = require("../lune_packages/pathfs")
|
||||
|
||||
local Result = require("../lune_packages/result")
|
||||
local Option = require("../lune_packages/option")
|
||||
type Result<T, E> = Result.Result<T, E>
|
||||
type Option<T> = Option.Option<T>
|
||||
|
||||
local revTable = require("./utils/rev_table")
|
||||
local CommandBuilder = require("./utils/exec")
|
||||
local types = require("./utils/result_option_conv")
|
||||
local Option = types.Option
|
||||
type Option<T> = types.Option<T>
|
||||
local Result = types.Result
|
||||
type Result<T, E> = types.Result<T, E>
|
||||
|
||||
export type CompressionFormat = "TarGz" | "TarXz" | "Zip"
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
local net = require("@lune/net")
|
||||
|
||||
local Result = require("../lune_packages/result")
|
||||
local Option = require("../lune_packages/option")
|
||||
type Result<T, E> = Result.Result<T, E>
|
||||
type Option<T> = Option.Option<T>
|
||||
|
||||
local copy = require("./utils/copy")
|
||||
local types = require("./utils/result_option_conv")
|
||||
local Option = types.Option
|
||||
local Result = types.Result
|
||||
type Option<T> = types.Option<T>
|
||||
type Result<T, E> = types.Result<T, E>
|
||||
|
||||
local Github = {}
|
||||
export type Github = typeof(setmetatable(Github :: GithubFields, { __index = Github }))
|
||||
|
|
|
@ -15,9 +15,11 @@ local serde = require("@lune/serde")
|
|||
local pathfs = require("../lune_packages/pathfs")
|
||||
local dirs = require("../lune_packages/dirs")
|
||||
|
||||
local types = require("./utils/result_option_conv")
|
||||
local Option = types.Option
|
||||
type Option<T> = types.Option<T>
|
||||
local Result = require("../lune_packages/result")
|
||||
local ResultExt = require("./utils/ext/result")
|
||||
local Option = require("../lune_packages/option")
|
||||
type Result<T, E> = Result.Result<T, E>
|
||||
type Option<T> = Option.Option<T>
|
||||
|
||||
local Github = require("./github")
|
||||
local PlatformDescriptor = require("./platform/descriptor")
|
||||
|
@ -54,7 +56,7 @@ local function downloadAndDecompress(asset: {
|
|||
return error(`Failed to download asset {asset.name}: HTTP Code {contentsResp.statusCode}`)
|
||||
end
|
||||
|
||||
return compression.decompress[format](buffer.fromstring(contentsResp.body)):ok() :: Option<pathfs.Path>
|
||||
return ResultExt.ok(compression.decompress[format](buffer.fromstring(contentsResp.body)))
|
||||
end) :: Option<pathfs.Path>
|
||||
end
|
||||
|
||||
|
@ -89,7 +91,9 @@ function runTool(tool: ToolId | pathfs.Path): number
|
|||
-- FIXME: `process.spawn` has a bug where interactive features don't
|
||||
-- forward properly
|
||||
local toolId = tool :: ToolId
|
||||
local path = if toolId.alias ~= nil then LINK_INSTALL_DIR:join(toolAliasOrDefault(toolId)) else tool :: pathfs.Path
|
||||
local path = if (toolId :: any).alias ~= nil
|
||||
then LINK_INSTALL_DIR:join(toolAliasOrDefault(toolId))
|
||||
else tool :: pathfs.Path
|
||||
|
||||
return process.spawn(path:toString(), process.args, {
|
||||
cwd = process.cwd,
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
local process = require("@lune/process")
|
||||
local detection = require("./detection")
|
||||
|
||||
local types = require("../utils/result_option_conv")
|
||||
local Option = types.Option
|
||||
type Option<T> = types.Option<T>
|
||||
local Option = require("../../lune_packages/option")
|
||||
type Option<T> = Option.Option<T>
|
||||
|
||||
export type Arch = process.Arch | "arm" | "x86"
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@ local toolchain = require("./toolchain")
|
|||
local result = require("./result")
|
||||
local detectFromExecutable = require("./detection/executable")
|
||||
|
||||
local types = require("../utils/result_option_conv")
|
||||
local Option = types.Option
|
||||
local Result = types.Result
|
||||
type Option<T> = types.Option<T>
|
||||
type Result<T, E> = types.Result<T, E>
|
||||
local Result = require("../../lune_packages/result")
|
||||
local Option = require("../../lune_packages/option")
|
||||
local OptionExt = require("../utils/ext/option")
|
||||
type Result<T, E> = Result.Result<T, E>
|
||||
type Option<T> = Option.Option<T>
|
||||
|
||||
local PlatformDescriptor = {}
|
||||
export type PlatformDescriptor = {
|
||||
|
@ -63,7 +63,8 @@ function PlatformDescriptor.fromExecutable(path: string): result.PlatformResult<
|
|||
}
|
||||
end) :: Option<PlatformDescriptor>
|
||||
|
||||
return platformDesc:okOr(
|
||||
return OptionExt.okOr(
|
||||
platformDesc,
|
||||
"NoExecutableDetected" :: result.PlatformError
|
||||
) :: result.PlatformResult<PlatformDescriptor>
|
||||
end
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
local String = require("../../utils/string")
|
||||
|
||||
local types = require("../../utils/result_option_conv")
|
||||
local Option = types.Option
|
||||
type Option<T> = types.Option<T>
|
||||
local Option = require("../../../lune_packages/option")
|
||||
type Option<T> = Option.Option<T>
|
||||
|
||||
local function charWordSep(char: string)
|
||||
return char == " " or char == "-" or char == "_"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
local types = require("../utils/result_option_conv")
|
||||
type Result<T, E> = types.Result<T, E>
|
||||
local Result = require("../../lune_packages/result")
|
||||
type Result<T, E> = Result.Result<T, E>
|
||||
|
||||
export type PlatformError = "NoPatternDetected" | "NoExecutableDetected" | "UnknownExecutableField"
|
||||
export type PlatformResult<T> = Result<T, PlatformError>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
local types = require("../utils/result_option_conv")
|
||||
local Option = types.Option
|
||||
type Option<T> = types.Option<T>
|
||||
local Option = require("../../lune_packages/option")
|
||||
type Option<T> = Option.Option<T>
|
||||
|
||||
local TOOLCHAINS: { Toolchain } = { "msvc", "gnu", "musl" }
|
||||
export type Toolchain = "msvc" | "gnu" | "musl"
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
local process = require("@lune/process")
|
||||
local task = require("@lune/task")
|
||||
|
||||
local types = require("../utils/result_option_conv")
|
||||
local Option = types.Option
|
||||
type Option<T> = types.Option<T>
|
||||
local Option = require("../../lune_packages/option")
|
||||
type Option<T> = Option.Option<T>
|
||||
|
||||
local CommandBuilder = {}
|
||||
type CommandBuilderFields = {
|
||||
|
@ -34,10 +33,9 @@ export type ChildStatus = { ok: boolean, code: number, io: {
|
|||
stderr: string,
|
||||
} }
|
||||
|
||||
-- FIXME: remove unknown usage
|
||||
local DEFAULT_STDIO_STRATEGY: IoStrategyMapping = {
|
||||
stdout = Option.Some("pipe" :: StdioStrategy) :: Option<unknown>,
|
||||
stderr = Option.Some("pipe" :: StdioStrategy) :: Option<unknown>,
|
||||
stdout = Option.Some("pipe" :: StdioStrategy),
|
||||
stderr = Option.Some("pipe" :: StdioStrategy),
|
||||
}
|
||||
local DEFAULT_RETRIES = 0
|
||||
local DEFAULT_IGNORE_ERRORS = false
|
||||
|
@ -84,11 +82,10 @@ function CommandBuilder.withStdioStrategy(
|
|||
self: CommandBuilder,
|
||||
strategy: StdioStrategy | IoStrategyMapping
|
||||
): CommandBuilder
|
||||
-- FIXME: remove unknown usage
|
||||
self.stdioStrategy = Option.Some(if typeof(strategy) == "string"
|
||||
then {
|
||||
stdout = Option.Some(strategy) :: Option<unknown>,
|
||||
stderr = Option.Some(strategy) :: Option<unknown>,
|
||||
stdout = Option.Some(strategy),
|
||||
stderr = Option.Some(strategy),
|
||||
}
|
||||
else strategy) :: Option<IoStrategyMapping>
|
||||
return self
|
||||
|
@ -124,12 +121,8 @@ function CommandBuilder.intoChildProcess(self: CommandBuilder): ChildProcess
|
|||
else `{self.program} {argsList} & echo $!`,
|
||||
{},
|
||||
{
|
||||
stdio = self
|
||||
.stdioStrategy
|
||||
-- FIXME: remove unknown usage
|
||||
:orOpt(
|
||||
Option.Some(DEFAULT_STDIO_STRATEGY) :: Option<unknown>
|
||||
)
|
||||
stdio = self.stdioStrategy
|
||||
:orOpt(Option.Some(DEFAULT_STDIO_STRATEGY))
|
||||
:map(function(mappings: IoStrategyMapping)
|
||||
local translatedMappings: process.SpawnOptionsStdio = {}
|
||||
for field, value in mappings do
|
||||
|
|
16
toolchainlib/src/utils/ext/option.luau
Normal file
16
toolchainlib/src/utils/ext/option.luau
Normal file
|
@ -0,0 +1,16 @@
|
|||
--> Non-exhaustive set of extensions for the `Option<T>` type
|
||||
|
||||
local Option = require("../../../lune_packages/option")
|
||||
local Result = require("../../../lune_packages/result")
|
||||
|
||||
local OptionExt = {}
|
||||
|
||||
function OptionExt.okOr<T, E>(self: Option.Option<T>, err: E): Result.Result<T, E>
|
||||
return self:mapOrElse(function()
|
||||
return Result.Err(err)
|
||||
end, function(val)
|
||||
return Result.Ok(val)
|
||||
end) :: Result.Result<T, E>
|
||||
end
|
||||
|
||||
return OptionExt
|
14
toolchainlib/src/utils/ext/result.luau
Normal file
14
toolchainlib/src/utils/ext/result.luau
Normal file
|
@ -0,0 +1,14 @@
|
|||
--> Non-exhaustive set of extensions for the `Result<T, E>` type
|
||||
|
||||
local Option = require("../../../lune_packages/option")
|
||||
local Result = require("../../../lune_packages/result")
|
||||
|
||||
local ResultExt = {}
|
||||
|
||||
function ResultExt.ok<T, E>(self: Result.Result<T, E>): Option.Option<T>
|
||||
return self:mapOr(Option.None, function(val: T)
|
||||
return Option.Some(val)
|
||||
end) :: Option.Option<T>
|
||||
end
|
||||
|
||||
return ResultExt
|
|
@ -1,34 +0,0 @@
|
|||
--> Non-exhaustive set of extensions for Option<->Result conversion
|
||||
|
||||
local OptionImpl = require("../../lune_packages/option")
|
||||
local ResultImpl = require("../../lune_packages/result")
|
||||
|
||||
local Option = {}
|
||||
local Result = {}
|
||||
|
||||
export type Option<T> = OptionImpl.Option<T> & typeof(Option)
|
||||
export type Result<T, E> = ResultImpl.Result<T, E> & typeof(Result)
|
||||
|
||||
function Option.okOr<T, E>(self: Option<T>, err: E): Result<T, E>
|
||||
return self:mapOrElse(function()
|
||||
return ResultImpl.Err(err)
|
||||
end, function(val)
|
||||
return ResultImpl.Ok(val)
|
||||
end) :: Result<T, E>
|
||||
end
|
||||
|
||||
function Result.ok<T, E>(self: Result<T, E>): Option<T>
|
||||
return self:mapOr(OptionImpl.None, function(val: T)
|
||||
return OptionImpl.Some(val)
|
||||
end) :: Option<T>
|
||||
end
|
||||
|
||||
return {
|
||||
Option = setmetatable(OptionImpl, {
|
||||
__index = Option,
|
||||
}),
|
||||
|
||||
Result = setmetatable(ResultImpl, {
|
||||
__index = Result,
|
||||
}),
|
||||
}
|
Loading…
Reference in a new issue