This require mode is meant to be used for resolving content using regular file paths.

**_Warning!_ ** The _path_ require mode should not be confused with the _luau_ require mode. Both require modes are used with strings looking like file paths, but they resolve to actual files differently.

Once enabled, darklua will find all require calls made with strings (single or double quotes) and resolve them.

## Bundling Support

It can be configured in the **bundle** part of the configuration file. For a quick overview of the bundling configuration, see [the documentation page](https://darklua.com/docs/bundle/).

## Configuration Overview

The path require mode can be defined as the string ‘path’ to use all the default values, or with its object format:

      name: "path",

      // optional (defaults to 'init')
      module_folder_name: "init",

      // optional
      sources: {
        pkg: "./Packages",
      },

      // optional (defaults to true)
      use_luau_configuration: true,

## Path Resolution

The first step consist of figuring out the head of the path or where to start looking for the resource:

  * **if the path starts with `.` or `..`:** the path is considered relative to the file where the require call is made

  * **if the path starts with `/`:** the path is considered like a regular absolute path

  * **else:** the first component of the path is used to find a matching [source](https://darklua.com/docs/path-require-mode/#sources)

The next step is to resolve the tail of the path. Darklua will find the first available file based on the given path:

  1. the given path

  2. the given path with a `luau` extension

  3. the given path with a `lua` extension

  4. the given path joined with the module folder name

  5. (if the module folder name does not have an extension) the given path joined with the module folder name and a `luau` extension

  6. (if the module folder name does not have an extension) the given path joined with the module folder name and a `lua` extension

Here is a concrete example of these steps with a require to `./example`. darklua will try the following paths and find the first file:

  1. `./example`

  2. `./example.luau`

  3. `./example.lua`

  4. `./example/init`

  5. `./example/init.luau`

  6. `./example/init.lua`

## Module Folder Name

When requiring a folder, this mode will look into the folder for a file named by the given value of the `module_folder_name` parameter. The default value is `init`.

For example, to configure darklua to use `index.lua` (or `index.luau`) similar to what is used in JavaScript, set the parameter to `index`.

To bundle with `index` files, provide this configuration:

      bundle: {
        require_mode: {
          name: "path",
          // folders with a `index.lua` or `index.luau` file
          // can be required
          module_folder_name: "index",
        },
      },

Or when using the `convert_require` rule, provide this configuration:

      rules: [
          rule: "convert_require",
          current: {
            name: "path",
            // folders with a `index.lua` or `index.luau` file
            // can be required
            module_folder_name: "index",
          },
          target: "roblox",
        },
      ],

## Sources

When a path do not start with `.`, `..` or `/`, their first component is used to find its associated source location. These locations can be configured with the `sources` parameter of the path require mode configuration.

Relative paths are resolved based on the configuration file location.

### Example

Given this configuration file for bundling:

      bundle: {
        require_mode: {
          name: "path",
          sources: {
            @pkg: "./Packages",
            // you can also map directly to a file (Lua or
            // any supported data file)
            images: "./assets/image-links.json",
          },
        },
      },

It is possible to make these require call in any file:

    local Promise = require("@pkg/Promise")
    local images = require("images")

## Luau Configuration Files

Luau configuration files are named `.luaurc` and they can contain an `aliases` parameter which acts like the [sources](https://darklua.com/docs/path-require-mode/#sources) parameter in darklua.

The value of `use_luau_configuration` will change how darklua finds new sources. Before looking at the [sources](https://darklua.com/docs/path-require-mode/#sources) value, darklua will attempt to find the nearest `.luaurc` configuration file to each file it processes. If it finds one, it will load the aliases.

This behavior is enabled by default. It can be disabled by setting `use_luau_configuration` to `false`.


Added in 0.17.2

Global function declarations will be transformed into assignment statements. This rule handles simple global functions, functions with field access (`module.function`), and method definitions (`object:method`).

When converting method syntax (`:method`), the rule automatically adds `self` as the first parameter to maintain the same behavior.

Note that, depending on your Lua runtime implementation, you may no longer be able to use reflection-like APIs (eg `debug.info`) to acquire the name of the function, or the function name may be missing from stack traces of `error` invocations.

## Examples

InputOutput

    function foo(a, b)
        return a + b
    end

    foo=function(a, b)
    return a + b
    end

InputOutput

    function obj:method(value)
        return self.field + value
    end

    obj.method=function(self, value)
    return self.field + value
    end

Input| Output

    function foo(a, b)
        return a + b
    end

    foo=function(a, b)
    return a + b
    end

    function obj:method(value)
        return self.field + value
    end

    obj.method=function(self, value)
    return self.field + value
    end


Added in 0.14.1

This rule removes all `continue` statements and replaces them with code that only use `break` statements.

**Note:** this rule is useful if you are converting Luau code into regular Lua code.

## Examples

InputOutput

    for i = 1, 10 do
        if i == 1 then
            continue
        end
        print(i)
    end

    for i = 1, 10 do
    local __DARKLUA_CONTINUE_1=false repeat    if i == 1 then
    __DARKLUA_CONTINUE_1=true        break
        end
        print(i)
    __DARKLUA_CONTINUE_1=true until true if not __DARKLUA_CONTINUE_1 then break end end

Input| Output

    for i = 1, 10 do
        if i == 1 then
            continue
        end
        print(i)
    end

    for i = 1, 10 do
    local __DARKLUA_CONTINUE_1=false repeat    if i == 1 then
    __DARKLUA_CONTINUE_1=true        break
        end
        print(i)
    __DARKLUA_CONTINUE_1=true until true if not __DARKLUA_CONTINUE_1 then break end end


This require mode is specific to Roblox, as it will interpret require calls to Roblox instances. Right now, it is only available to use as the target require mode when using the [`convert_require` rule](https://darklua.com/docs/rules/convert_require/).

The Roblox require mode can be defined as the string ‘roblox’ to use all the default values, or with its object format:

      name: "roblox",

      // optional
      rojo_sourcemap: "./path-to/sourcemap.json",

      // optional (defaults to "find_first_child")
      indexing_style: "find_first_child", // "wait_for_child" or "property"

## With a Rojo Sourcemap

A Rojo sourcemap file can be provided to darklua to directly get a file location in the DataModel.

      rules: [
          rule: "convert_require",
          current: "path",
          target: {
            name: "roblox",
            rojo_sourcemap: "./path-to/sourcemap.json",
          },
        },
      ],

## Without a Rojo sourcemap

When a sourcemap is not provided, darklua will assume that all paths are relative to the file you are requiring from and that the files are laid out in the same structure in the Roblox DataModel.

For example, if a module is requiring another module as:

  * `"./MyClass"`: then it will convert to `script.Parent:FindFirstChild("MyClass")`
  * `"../MyClass"`: then it will convert to `script.Parent.Parent:FindFirstChild("MyClass")`

If the module converts to a ModuleScript instance (because it is called `init.lua` in Rojo),

  * `"./MyClass"`: will convert to `script:FindFirstChild("MyClass")`
  * `"../MyClass"`: will convert to `script.Parent:FindFirstChild("MyClass")`

## Indexing Style

This parameter controls how instance paths should be generated.

There are 3 different indexing style available:

  * `find_first_child`: uses the [`FindFirstChild`](https://create.roblox.com/docs/reference/engine/classes/Instance#FindFirstChild) method for getting instances (default value)
  * `wait_for_child`: uses the [`WaitForChild`](https://create.roblox.com/docs/reference/engine/classes/Instance#WaitForChild) method for getting instances
  * `property`: uses property-like way of getting child instances, using a period ”.” (note that this kind of indexing may collide with Instance properties!)

Here is an example of how to configure the `convert_require` rule to use the `wait_for_child` indexing style:

      rules: [
          rule: "convert_require",
          current: "path",
          target: {
            name: "roblox",
            // indexing_style can be "find_first_child", "wait_for_child" or "property"
            indexing_style: "wait_for_child",
          },
        },
      ],


Added in 0.3.1

When a condition in a if branch (`if condition then` or `elseif condition then`) can be evaluated to a known value, the if statement (or if expression) is modified to remove branches that become useless.

    if unknown then
        return 2
    elseif true then
        return 1
    else
        return 0
    end

Since the second branch is always true, the else block becomes superfluous. As such, this rule would output:

    if unknown then
        return 2
    elseif true then
        return 1
    end

This rule can also turn if statements into do statements in certain cases:

    if true then
        return 2
    elseif unknown then
        return 1
    else
        return 0
    end

Since the first branch is always true, all other branches are useless, so this rule would output:

    do
        return 2
    end

This rule is influenced by the evaluation system of darklua. The more darklua can evaluate code, the better this rule can be applied.

## Examples

InputOutput

    return if true then value else default

    return value

InputOutput

    return if false then value else default

    return default

InputOutput

    if false then
        local sum = 0
        for _, element in ipairs(array) do
            sum = sum + element
        end
        print("sum of array:", sum)
    end

Input| Output

    return if true then value else default

    return value

    return if false then value else default

    return default

    if false then
        local sum = 0
        for _, element in ipairs(array) do
            sum = sum + element
        end
        print("sum of array:", sum)
    end


Added in 0.10.0

## Parameters

Name| Type| Description
---|---|---
**current**| `require mode`| The require mode used in the input code
**target**| `require mode`| The require mode used to generate the new require calls

This rule is particularly useful if you are writing Lua code that needs to be portable to Roblox, as you can automatically convert requires using file paths (like “./src/mod.lua”) to different path system (like the luau module paths used by [Lune](https://lune-org.github.io/docs/)) Roblox instances.

Right now, the current and target require modes have certain restrictions:

Mode | path | luau | roblox
---|---|---|---
current | ✅ | ✅ | ❌
target | ✅ | ✅ | ✅

## Configuration Overview

Here is an overview of the rule configuration format:

      rule: "convert_require",
      current: {
        name: "path",

        // optional (defaults to 'init')
        module_folder_name: "init",

        // optional
        sources: {
          "@pkg": "./Packages",
        },
      },
      target: {
        name: "roblox",

        // optional
        rojo_sourcemap: "./path-to/sourcemap.json",

        // optional (defaults to 'find_first_child')
        indexing_style: "find_first_child", // 'wait_for_child' or 'property'
      },

For more information about how to configure each of require mode, visit:

  * [path require mode documentation](https://darklua.com/docs/path-require-mode/)

  * [luau require mode documentation](https://darklua.com/docs/path-require-mode/)

  * [roblox require mode documentation](https://darklua.com/docs/roblox-require-mode/)


Added in 0.8.0

This rule removes trailing `nil` values in local assignments. Additionally, it will trim unnecessary expressions in assignments when they do not cause any side-effects.

## Examples

InputOutput

    local var = nil

    local var

InputOutput

    local a, b, c = 1, nil, nil

    local a, b,c = 1

InputOutput

    local a, b = nil, call()

    local b ,a=(call())

InputOutput

    local var = call(), otherValue, true

    local var = call()

Input| Output

    local var = nil

    local var

    local a, b, c = 1, nil, nil

    local a, b,c = 1

    local a, b = nil, call()

    local b ,a=(call())

    local var = call(), otherValue, true

    local var = call()


Added in 0.8.0

When this rule encounters a `return` statement at the end of a `do` statement block, it will clear out the next statements of the outer block.

This rule is effective when applied after rules that may produce do statements with return statements, like .

For example, given the following code:

    do
        local function process()
            -- ...
        end

        return process
    end

    local function otherImplementation()
        -- ...
    end

    return otherImplementation

The rule will clear the `otherImplementation` since `process` will always be returned first. It will produce the following code:

    do
        local function process()
            -- ...
        end

        return process
    end


Added in 0.3.5

## Parameters

Name| Type| Description| Default
---|---|---|---
**identifier**| `string`| The name of the global variable|
value| `any`| The value to inject| `nil`
env| `string`| An environment variable to read the value from (added in v0.7.0)|
env_json| `string`| An environment variable to read the json-encoded value from (added in v0.17.0)|
default_value| `any`| The default value when using an environment variable that is not defined (added in v0.17.0)|

This rule will find a global variable and replace it with a given value. The value can be defined in the rule configuration or taken from an environment variable.

To inject a static value, use the `value` property.

      rule: "inject_global_value",
      identifier: "GLOBAL",
      value: true,

If `value` is not specified, the `env` property can be defined to read an environment variable that will be read into a string.

      rule: "inject_global_value",
      identifier: "GLOBAL",
      env: "SOME_VARIABLE",

Alternatively, the `env_json` property allows you to read a JSON-encoded value (`json5` is supported) from an environment variable. This is useful for injecting any data like booleans or structured data like arrays or objects.

      rule: "inject_global_value",
      identifier: "SETTINGS",
      env_json: "APP_SETTINGS",

When using the `env` or `env_json` property, the `default_value` property can be used to provide a fallback value when the environment variable is not defined. This prevents the rule from using `nil` as the default value.

      rule: "inject_global_value",
      identifier: "FEATURE_FLAG",
      env: "ENABLE_FEATURE",
      default_value: false,

This rule can be used in combination with the `remove_unused_if_branch`, `compute_expression`, and other rules, to eliminate dead branches. In addition to making your code smaller, it should make it faster (depending on how hot the code path is) since it is eliminating branch condition evaluations at client-side runtime.

## Examples

InputOutput

    if _G.AMOUNT > 10 or _G.CONSTANT ~= nil then
      --[[ ... ]]
    end

    if 11> 10 or 'Hello'~= nil then
      --[[ ... ]]
    end

InputOutput

    if _G.DEBUG then
      print('Debug information')
    end

    if true then
      print('Debug information')
    end

Input| Output

    if _G.AMOUNT > 10 or _G.CONSTANT ~= nil then
      --[[ ... ]]
    end

    if 11> 10 or 'Hello'~= nil then
      --[[ ... ]]
    end

    if _G.DEBUG then
      print('Debug information')
    end

    if true then
      print('Debug information')
    end


Added in 0.17.0

This rule transforms Luau-specific number literals into Lua compatible number literals. It converts binary literals (prefixed with `0b` or `0B`) to their hexadecimal equivalents. It also removes underscores used as digit separators in numbers.

## Examples

InputOutput

    print(0b1000_0001)

    print(0x81)

InputOutput

    return 0xA000_FFFF

    return 0xA000FFFF

Input| Output

    print(0b1000_0001)

    print(0x81)

    return 0xA000_FFFF

    return 0xA000FFFF


Added in 0.9.0

This rule can be particularly useful to convert Luau code to Lua.

## Examples

InputOutput

    counter += 1

    counter =counter+ 1

InputOutput

    object.prop -= 1

    object.prop =object.prop- 1

InputOutput

    object.message ..= ' (context: ' .. context .. ')'

    object.message =object.message.. ' (context: ' .. context .. ')'

Input| Output

    counter += 1

    counter =counter+ 1

    object.prop -= 1

    object.prop =object.prop- 1

    object.message ..= ' (context: ' .. context .. ')'

    object.message =object.message.. ' (context: ' .. context .. ')'


# util.luau

A collection of useful utilities for Luau.

util.luau is a collection of type-safe utilities for Luau, designed to be
runtime agnostic with out-of-the-box support for Roblox and Lune.

Learn more in the [documentation](https://lukadev-0.github.io/util.luau).


## Type-safe

We try to make the utilities as type-safe as possible, so you can catch bugs sooner, and have better autocompletion.


# Reference

Package| Description
[future](https://lukadev-0.github.io/util.luau/reference/future)| Represent asynchronous operations.
[option](https://lukadev-0.github.io/util.luau/reference/option)| Values that may or may not exist.
[result](https://lukadev-0.github.io/util.luau/reference/result)| Represent fallible operations.
[std](https://lukadev-0.github.io/util.luau/reference/std)| Runtime agnostic access to standard libraries.
[threadpool](https://lukadev-0.github.io/util.luau/reference/threadpool)| Spawn threads with reuse.
[timer](https://lukadev-0.github.io/util.luau/reference/timer)| Schedule code to run at a future time or at an interval.


# Getting Started

util.luau is a collection of useful utilities for Luau, designed to work on any Luau runtime.

## Installation

### With Wally

The recommended way to install util.luau is with [Wally](https://wally.run), a package manager for Roblox. Each utility is published as a separate package, the package name will be specified in the documentation for each utility.

If you're using [Lune](https://lune-org.github.io/lune), you can use [this fork of Wally](https://github.com/VirtualButFake/wally) by [VirtualButFake](https://github.com/VirtualButFake).

#### Accessing types

You may find that you cannot access the types of the packages you install with Wally. This is because Wally generates linker scripts for the dependencies, which don't re-export the types. To fix this, you need to use the [wally-package-types](https://github.com/JohnnyMorganz/wally-package-types) tool after running `wally install`.

If you're using the fork of Wally for Lune, you can use [lune-wally-package-types](https://github.com/VirtualButFake/lune-wally-package-types).

### With pesde

You can also install util.luau with [pesde](https://pesde.daimond113.com), unlike Wally, pesde supports types automatically, so you don't need to use any additional tools.

### Roblox Models

You can also install `util.luau` through `.rbxm` files, which are available in the [releases](https://github.com/lukadev-0/util.luau/releases), each package has its own `.rbxm` file, and a `util.rbxm` is also available which contains every package.

## Learning

The **Guide** is a great place to start to learn about some common utilities and how to use them.

If you'd like to see the full list of utilities and their APIs, check out the [reference](https://lukadev-0.github.io/util.luau/reference/).


# result

[View Source](https://github.com/lukadev-0/util.luau/blob/main/packages/result/init.luau)

The `result` package provides the `Result<T, E>` type, which is a type that represents a value that may or may not exist, which can be used as an alternative to throwing errors through `error()`.

Results force you to explicitly handle errors, so you don't have to worry about unhandled errors that may break your code.

This utility is inspired by the [`Result` type in Rust](https://doc.rust-lang.org/std/result/enum.Result.html).

## Installation

Learn more about [installation](https://lukadev-0.github.io/util.luau/docs/getting-started#installation).

wallypesde

toml

    [dependencies]
    result = "lukadev-0/result@1.2.1"

sh

    pesde add lukadev_0/result@1.2.1

## Immutability

The `Result` type is immutable, meaning that once an `Result` is created, it cannot be modified.

However, the value inside the `Result` may be mutable, so it is important to be aware of this when working with `Result` values.

## Static Functions

### Result.Ok

lua

    function Result.Ok<T>(value: T): Result<T, any>

Creates a new `Ok` with the given value.

#### Example

lua

    local result = Result.Ok(5)
    assert(result:isOk())

### Result.Err

lua

    function Result.Err<E>(error: E): Result<any, E>

Creates a new `Err` with the given error.

#### Example

lua

    local result = Result.Err("An error occurred")
    assert(result:isErr())

### Result.try

lua

    function Result.try<T, U...>(f: (U...) -> T, ...: U...): Result<T, unknown>

Calls the given function and returns a `Result` with the result of the function. If the function throws an error, it will be caught and returned as an `Err`.

This is like `pcall()`, but it returns a `Result`.

#### Example

lua

    local ok = Result.try(function()
      return 5
    end)

    assert(ok == Result.Ok(5))

    local err = Result.try(function()
      error("An error occurred")
    end)

    assert(err == Result.Err("An error occurred"))

### Result.is

lua

    function Result.is(value: any): boolean

Returns true if the given value is a `Result`.

#### Example

lua

    assert(Result.is(Result.Ok(5)))
    assert(Result.is(Result.Err("An error occurred")))
    assert(not Result.is(5)

## Instance Functions

### Result:isOk

lua

    function Result:isOk(): boolean

Returns true if the `Result` is an `Ok`.

#### Example

lua

    local result = Result.Ok(5)
    assert(result:isOk())

### Result:isOkAnd

lua

    function Result:isOkAnd(f: (T) -> boolean): boolean

Returns true if the result is `Ok` and the value matches the given predicate.

#### Example

lua

    local result = Result.Ok(5)
    assert(result:isOkAnd(function(value)
      return value == 5
    end))

### Result:isErr

lua

    function Result:isErr(): boolean

Returns true if the `Result` is an `Err`.

#### Example

lua

    local result = Result.Err("An error occurred")
    assert(result:isErr())

### Result:isErrAnd

lua

    function Result:isErrAnd(f: (E) -> boolean): boolean

Returns true if the result is `Err` and the error matches the given predicate.

#### Example

lua

    local result = Result.Err("An error occurred")
    assert(result:isErrAnd(function(error)
      return error == "An error occurred"
    end))

### Result:map

lua

    function Result:map<U>(f: (T) -> U): Result<U, E>

Calls the given function with the contained `Ok` value and returns a `Result` with the result of the function. Leaving an `Err` value untouched.

#### Example

lua

    local result = Result.Ok(5)
    local mapped = result:map(function(value)
      return value * 2
    end)

    assert(mapped == Result.Ok(10))

### Result:mapOr

lua

    function Result:mapOr<U>(default: U, f: (T) -> U): U

Calls the given function with the contained `Ok` value and returns the result, otherwise returns the given default value.

#### Example

lua

    local ok = Result.Ok(5):mapOr(0, function(value)
      return value * 2
    end)

    assert(ok == 10)

    local err = Result.Err("An error occurred"):mapOr(0, function(value)
      return value * 2
    end)

    assert(err == 0)

### Result:mapOrElse

lua

    function Result:mapOrElse<U, V>(default: (E) -> U, f: (T) -> V): U | V

Calls the given function with the contained `Ok` value and returns the result, otherwise calls the given function with the contained `Err` value.

#### Example

lua

    local ok = Result.Ok(5):mapOrElse(
      function(error)
        return error
      end,
      function(value)
        return value * 2
      end
    )

    assert(ok == 10)

    local err = Result.Err("An error occurred"):mapOrElse(
      function(error)
        return error
      end,
      function(value)
        return value * 2
      end
    )

    assert(err == "An error occurred")

### Result:mapErr

lua

    function Result:mapErr<F>(f: (E) -> F): Result<T, F>

Calls the given function with the contained `Err` value and returns a `Result` with the result of the function. Leaving an `Ok` value untouched.

#### Example

lua

    local result = Result.Err("An error occurred")
    local mapped = result:mapErr(function(error)
      return error:upper()
    end)

    assert(mapped == Result.Err("AN ERROR OCCURRED"))

### Result:expect

lua

    function Result:expect(message: string): T

Unwraps the `Ok` value, returning it. If the value is an `Err`, it will throw an error with the given message.

THROWS

This function may throw an error.

#### Example

lua

    local result = Result.Ok(5)
    assert(result:expect("expected a value") == 5)

### Result:unwrap

lua

    function Result:unwrap(): T

Unwraps the `Ok` value, returning it. If the value is an `Err`, it will throw an error.

THROWS

This function may throw an error.

#### Example

lua

    local ok = Result.Ok(5)
    assert(ok:unwrap() == 5)

    local err = Result.Err("An error occurred")
    err:unwrap() -- throws "An error occurred"

### Result:expectErr

lua

    function Result:expectErr(message: string): E

Unwraps the `Err` value, returning it. If the value is an `Ok`, it will throw an error with the given message.

THROWS

This function may throw an error.

#### Example

lua

    local result = Result.Err("An error occurred")
    assert(result:expectErr("expected an error") == "An error occurred")

### Result:unwrapErr

lua

    function Result:unwrapErr(): E

Unwraps the `Err` value, returning it. If the value is an `Ok`, it will throw an error.

THROWS

This function may throw an error.

#### Example

lua

    local err = Result.Err("An error occurred")
    assert(err:unwrapErr() == "An error occurred")

    local ok = Result.Ok(5)
    ok:unwrapErr() -- throws 5

### Result:andRes

lua

    function Result:andRes<U>(res: Result<U, E>): Result<U, E>

Returns `res` if the result is `Ok`, otherwise returns the `Err`.

#### Example

lua

    local ok = Result.Ok(5)
    local res = Result.Ok(10)
    assert(ok:andRes(res) == res)

    local err = Result.Err("An error occurred")
    assert(err:andRes(res) == err)

### Result:andThen

lua

    function Result:andThen<U>(f: (T) -> Result<U, E>): Result<U, E>

Calls the given function with the contained `Ok` value and returns the result, otherwise returns the `Err`.

#### Example

lua

    local result = Result.Ok(5)
    local mapped = result:andThen(function(value)
      return Result.Ok(value * 2)
    end)

    assert(mapped == Result.Ok(10))

### Result:orRes

lua

    function Result:orRes<F>(res: Result<T, F>): Result<T, F>

Returns the `res` if the result is `Err`, otherwise returns the `Ok`.

#### Example

lua

    local ok = Result.Ok(5)
    local res = Result.Err("An error occurred")
    assert(ok:orRes(res) == ok)

    local err = Result.Err("An error occurred")
    assert(err:orRes(res) == res)

### Result:orElse

lua

    function Result:orElse<F>(f: (E) -> Result<T, F>): Result<T, F>

Calls the given function with the contained `Err` value and returns the result, otherwise returns the `Ok`.

#### Example

lua

    local result = Result.Err("An error occurred")
    local mapped = result:orElse(function(error)
      return Result.Err(error:upper())
    end)

### Result:unwrapOr

lua

    function Result:unwrapOr(default: T): T

Unwraps the `Ok` value, returning it. If the value is an `Err`, it will return the given default value.

#### Example

lua

    local ok = Result.Ok(5)
    assert(ok:unwrapOr(0) == 5)

    local err = Result.Err("An error occurred")
    assert(err:unwrapOr(0) == 0)

### Result:unwrapOrElse

lua

    function Result:unwrapOrElse(f: (E) -> T): T

Unwraps the `Ok` value, returning it. If the value is an `Err`, it will call the given function with the error and return the result.

#### Example

lua

    local ok = Result.Ok(5)
    assert(ok:unwrapOrElse(function(error)
      return error:upper()
    end) == 5)

    local err = Result.Err("An error occurred")
    assert(err:unwrapOrElse(function(error)
      return error:upper()
    end) == "AN ERROR OCCURRED")

### Result:match

lua

    function Result:match<U>(ok: (T) -> U, err: (E) -> U): U

Calls the given function with the contained `Ok` value and returns the result, otherwise calls the given function with the contained `Err` value.

#### Example

lua

    local result = Result.Ok(5)

    local value = result:match(
      function(value)
        return value * 2
      end,
      function(error)
        return error:upper()
      end
    )

    assert(value == 10)

### Result:unpack

lua

    function Result:unpack(): (T, E)

If the result is `Ok`, returns a tuple with the value and `nil`, otherwise returns a tuple with `nil` and the error.

TYPE-SAFETY

Due to Luau limitations, this function may not be type-safe.

You may access the `Ok` value even if the result is `Err`, it is important to check the `Err` value before using the `Ok` value.

#### Example

This is useful to propagate errors in a function.

lua

    local function doSomething(): Result<number, string>
      if math.random() > 0.5 then
        return Result.Ok(5)
      else
        return Result.Err("An error occurred")
      end
    end

    local function doSomethingElse(): Result<number, string>
      local result, err = doSomething():unpack()

      -- We propagate the error if there is one
      if err then
        return Result.Err(err)
      end

      return Result.Ok(result * 2)
    end

## Metamethods

### Result:__tostring

lua

    function Result:__tostring(): string

Called when `tostring()` is called on the `Result`.

Converts the `Result` to a string.

#### Example

lua

    local ok = Result.Ok(5)
    assert(tostring(ok) == "Result::Ok(5)")

    local err = Result.Err("An error occurred")
    assert(tostring(err) == "Result::Err(An error occurred)")

### Result:__eq

lua

    function Result:__eq(other: Result<T, E>): boolean

Called when the `==` operator is used on the `Result`.

Returns `true` if both results are `Ok` and their values are equal, or if both results are `Err` and their errors are equal.

#### Example

lua

    local ok1 = Result.Ok(5)
    local ok2 = Result.Ok(5)
    assert(ok1 == ok2)


# option

[View Source](https://github.com/lukadev-0/util.luau/blob/main/packages/option/init.luau)

The `option` package provides the `Option<T...>` type, which is a type that represents a value that may or may not exist, akin to `T | nil`.

This is useful to avoid `nil`-related bugs, which can cause bugs that are hard to track down.

This utility is inspired by the [`Option` type in Rust](https://doc.rust-lang.org/std/option/enum.Option.html).

## Installation

Learn more about [installation](https://lukadev-0.github.io/util.luau/docs/getting-started#installation).

wallypesde

toml

    [dependencies]
    option = "lukadev-0/option@1.2.1"

sh

    pesde add lukadev_0/option@1.2.1

## Immutability

The `Option` type is immutable, meaning that once an `Option` is created, it cannot be modified.

However, the value inside the `Option` may be mutable, so it is important to be aware of this when working with `Option` values.

## Static Properties

### Option.None

lua

    Option.None: Option<...any>

The option that does not contain a value.

#### Example

lua

    local none = Option.None
    assert(none:isNone())

## Static Functions

### Option.Some

lua

    function Option.Some<T...>(T...): Option<T...>

Creates a new `Some` with the given values. You must provide at least one value, otherwise an error will be thrown.

#### Example

lua

    local some = Option.Some(5, "foo", true)
    assert(some:isSome())

### Option.from

lua

    function Option.from<T>(value: T?): Option<T>

Creates a new `Option` from the given value. If the value is `nil`, it returns `None`, otherwise it returns `Some`.

#### Example

lua

    local some = Option.from(5)
    assert(some == Option.Some(5))

    local none = Option.from(nil)
    assert(none == Option.None)

### Option.is

lua

    function Option.is(value: any): boolean

Returns `true` if the given value is an `Option`, otherwise it returns `false`.

#### Example

lua

    local some = Option.Some(5)
    assert(Option.is(some))
    assert(Option.is(5) == false)

## Instance Functions

### Option:isSome

lua

    function Option:isSome(): boolean

Returns `true` if the `Option` is a `Some`, otherwise it returns `false`.

#### Example

lua

    local some = Option.Some(5)
    assert(some:isSome())

### Option:isSomeAnd

lua

    function Option:isSomeAnd(f: (T...) -> boolean): boolean

Returns `true` if the `Option` is a `Some` and the values satisfies the given predicate, otherwise it returns `false`.

#### Example

lua

    local some = Option.Some(5)
    assert(some:isSomeAnd(function(value)
      return value > 0
    end))

### Option:isNone

lua

    function Option:isNone(): boolean

Returns `true` if the `Option` is a `None`, otherwise it returns `false`.

#### Example

lua

    local none = Option.None
    assert(none:isNone())

### Option:expect

lua

    function Option:expect(message: string): T

Returns the value of the option if it is a `Some`, otherwise it throws an error with the given message.

THROWS

This function may throw an error.

#### Example

lua

    local some = Option.Some(5)
    assert(some:expect("expected a value") == 5)

    local none = Option.None
    none:expect("expected a value") -- throws "expected a value"

### Option:unwrap

lua

    function Option:unwrap(): T

Returns the value of the option if it is a `Some`, otherwise it throws an error.

THROWS

This function may throw an error.

#### Example

lua

    local some = Option.Some(5)
    assert(some:unwrap() == 5)

    local none = Option.None
    none:unwrap() -- throws "called `Option.unwrap()` on a `None` value"

### Option:unwrapOr

lua

    function Option:unwrapOr(T...): T...

Returns the value of the option if it is a `Some`, otherwise it returns the given default values.

#### Example

lua

    local some = Option.Some(5)
    assert(some:unwrapOr(10) == 5)

    local none = Option.None
    assert(none:unwrapOr(10) == 10)

### Option:unwrapOrElse

lua

    function Option:unwrapOrElse(f: () -> T...): T...

Returns the values of the option if it is a `Some`, otherwise it returns the result of the given function.

#### Example

lua

    local some = Option.Some(5)
    assert(some:unwrapOrElse(function()
      return 10
    end) == 5)

### Option:unwrapOrNil

lua

    function Option:unwrapOrNil(): T?

Returns the value of the option if it is a `Some`, otherwise it returns `nil`. Only works if the option contains a single value, any other values are ignored.

#### Example

lua

    local some = Option.Some(5)
    assert(some:unwrapOrNil() == 5)

    local none = Option.None
    assert(none:unwrapOrNil() == nil)

### Option:map

lua

    function Option:map<U...>(f: (T...) -> U...): Option<U...>

Returns the result of the given function wrapped in an `Option` if the option is `Some`, otherwise returns `None`.

#### Example

lua

    local some = Option.Some(5)
    local double = some:map(function(value)
      return value * 2
    end)

    assert(double == Option.Some(10))

### Option:mapOr

lua

    function Option:mapOr<U>(default: U, f: (T...) -> U): U

Returns the result of the given function if the option is `Some`, otherwise returns the given default value. The result may only contain one value, if you need multiple values, use `mapOrRest`.

#### Example

lua

    local some = Option.Some(5)
    assert(some:mapOr(15, function(value)
      return value * 2
    end) == 10)

    local none = Option.None
    assert(none:mapOr(15, function(value)
      return value * 2
    end) == 15)

### Option:mapOrRest

lua

    function Option:mapOrRest<U...>(f: (T...) -> U..., U...): U...

Returns the result of the given function if the option is `Some`, otherwise returns the given default values.

This is equivalent to `mapOr` but allows for multiple return values. The default values are provided after the function.

### Option:mapOrElse

lua

    function Option:mapOrElse<U...>(default: () -> U..., f: (T...) -> U...): U...

Returns the result of the given function if the option is `Some`, otherwise returns the result of calling the default function.

#### Example

lua

    local none = Option.None
    assert(none:mapOrElse(function()
      return 15
    end, function(value)
      return value * 2
    end) == 10)

### Option:andOpt

lua

    function Option:andOpt<U...>(other: Option<U...>): Option<U...>

Returns `None` if the option is `None`, otherwise returns the other option.

#### Example

lua

    local some = Option.Some(5)
    local other = Option.Some(10)
    assert(some:andOpt(other) == other)

    local none = Option.None
    assert(none:andOpt(other) == none)

### Option:andThen

lua

    function Option:andThen<U...>(f: (T...) -> Option<U...>): Option<U...>

Returns `None` if the option is `None`, otherwise returns the result of the given function.

#### Examples

lua

    local some = Option.Some(5)
    local double = some:andThen(function(value)
      return Option.Some(value * 2)
    end)

    assert(double == Option.Some(10))

### Option:filter

lua

    function Option:filter(f: (T...) -> boolean): Option<T>

Returns `None` if the option is `None`, otherwise calls the function with the values:

  * if the function returns `true`, returns the original option
  * if the function returns `false`, returns `None`

#### Examples

lua

    local some = Option.Some(5)
    local filtered = some:filter(function(value)
      return value > 0
    end)

    assert(filtered == some)

### Option:orOpt

lua

    function Option:orOpt(other: Option<T...>): Option<T...>

Returns the option if it is `Some`, otherwise returns the other option.

#### Example

lua

    local some = Option.Some(5)

    assert(some:orOpt(Option.Some(10)) == some)
    assert(some:orOpt(Option.None) == some)

    local none = Option.None
    assert(none:orOpt(Option.Some(10)) == Option.Some(10))
    assert(none:orOpt(Option.None) == none)

### Option:orElse

lua

    function Option:orElse(f: () -> Option<T...>): Option<T...>

Returns the option if it is `Some`, otherwise returns the result of calling the given function.

#### Example

lua

    local some = Option.Some(5)
    assert(some:orElse(function()
      return Option.Some(10)
    end) == some)

### Option:xor

lua

    function Option:xor(other: Option<T...>): Option<T...>

Returns `None` if both options are `Some` or `None`, otherwise returns the option.

#### Example

lua

    local some = Option.Some(5)
    local other = Option.Some(10)

    assert(some:xor(other) == Option.None)

### Option:match

lua

    function Option:match<U...>(f: {
      Some: (T...) -> U...,
      None: () -> U...
    }): U...

Takes a table containing a `Some` and `None` function. If the option is a `Some`, calls the `Some` function with the values of the option, otherwise calls the `None` function. The result of the function call is returned.

#### Example

lua

    local some = Option.Some(5)

    local result = some:match({
      Some = function(value)
        return value * 2
      end,
      None = function()
        return 20
      end
    })

    assert(result == 10)

### Option:join

lua

    function Option:join<U...>(other: Option<U...>): Option<(T..., U...)>

Joins the values of two options into a single option. If both options are `Some`, the values are joined into a single `Some`, otherwise `None` is returned.

#### Example

lua

    local some = Option.Some(1, 2)
    local other = Option.Some(3, 4)

    assert(some:join(other) == Option.Some(1, 2, 3, 4))

## Metamethods

### Option:__tostring

lua

    function Option:__tostring(): string

Called when `tostring()` is called on the `Option`.

Converts the `Option` to a string. The format of the returned string may change and should not be relied upon.

#### Example

lua

    local some = Option.Some(5)
    assert(tostring(some) == "Option::Some(5)")

    local none = Option.None
    assert(tostring(none) == "Option::None")

### Option:__eq

lua

    function Option:__eq(other: Option<T>): boolean

Called when the `==` operator is used on the `Option`.

Returns `true` if both options are `Some` and their values are equal, or if both options are `None`, otherwise returns `false`.

#### Example

lua

    local some = Option.Some(5)
    local other = Option.Some(5)

    assert(some == other)


# future

[View Source](https://github.com/lukadev-0/util.luau/blob/main/packages/future/init.luau)

A future represents a value that does not exist yet, but will exist at some point in the future.

Futures allow you to more easily compose asynchronous operations.

This utility is inspired by the [`Future` type in Rust](https://doc.rust-lang.org/std/future/trait.Future.html).

## Installation

Learn more about [installation](https://lukadev-0.github.io/util.luau/docs/getting-started#installation).

wallypesde

toml

    [dependencies]
    future = "lukadev-0/future@1.0.2"

sh

    pesde add lukadev_0/future@1.0.2

## Static Functions

### Future.new

lua

    function Future.new<T>(value: T) -> Future<T>

Creates a finished future with the given value.

#### Example

lua

    local fut = Future.new(5)
    assert(fut:now() == Option.Some(5))

### Future.never

lua

    function Future.never() -> Future<any>

Creates a pending future that will never finish.

#### Example

lua

    local fut = Future.never()
    assert(fut:now() == Option.None)

### Future.spawn

lua

    function Future.spawn<T, U...>(f: () -> T, ...: U...) -> Future<T>

Creates a future and spawns the function in a new thread. The future will resolve with the result of the function.

Throwing inside of the function will lead to undefined behavior.

#### Example

lua

    local function httpGet(url)
      -- does an HTTP request to url
    end

    local fut = Future.spawn(httpGet, "https://google.com/")
    local res = fut:await()

### Future.pending

lua

    function Future.pending<T>() -> (Future<T>, (T) -> ())

Returns a future and a function that, when called, will resolve the future with the given value.

#### Example

lua

    local fut: Future.Future<number>, resolve = Future.pending()

    resolve(5)
    assert(fut:now() == Option.Some(5))

### Future.fn

lua

    function Future.fn<T, V...>(f: (V...) -> T) -> (V...) -> Future<T>

Returns a function that, when called, creates a future and spawns the given function in a new thread. The future will resolve with the result of the function.

This allows you to convert a yielding function into a function that returns a Future.

#### Example

lua

    local function httpGet(url)
      -- does an HTTP request to url
    end

    local httpGetFut = Future.fn(httpGet)
    local fut = httpGetFut("https://google.com/")
    local res = fut:await()

### Future.all

lua

    function Future.all<T>(futures: { Future<T> }) -> Future<{ T }>

Returns a future that resolves once all the given futures have resolved. It resolves with a table of the resolved values.

This turns `{ Future<T> }` into `Future<{ T }>`.

#### Example

lua

    local fut1 = Future.new(5)
    local fut2 = Future.new(10)
    local fut3 = Future.new(15)

    local allFut = Future.all({ fut1, fut2, fut3 })

    local res = allFut:now():unwrap()
    assert(res[1] == 5)
    assert(res[2] == 10)
    assert(res[3] == 15)

### Future.race

lua

    function Future.race<T>(futures: { Future<T> }) -> Future<T>

Returns a future that resolves once the first of the given futures has resolved. It resolves with the value of the first resolved future. The results of the other futures are discarded.

This turns `{ Future<T> }` into `Future<T>`.

#### Example

lua

    local fut1 = Future.new(5)
    local fut2 = Future.new(10)
    local fut3 = Future.new(15)

    local raceFut = Future.race({ fut1, fut2, fut3 })

    local res = raceFut:now():unwrap()
    assert(res == 5)

## Instance Functions

### Future:isFinished

lua

    function Future:isFinished() -> boolean

Returns `true` if the future is finished, otherwise it returns `false`.

#### Example

lua

    local fut = Future.new(5)
    assert(fut:isFinished())

### Future:isPending

lua

    function Future:isPending() -> boolean

Returns `true` if the future is pending, otherwise it returns `false`.

#### Example

lua

    local fut = Future.never()
    assert(fut:isPending())

### Future:now

lua

    function Future:now() -> Option<T>

Returns the value of the future if it is finished, otherwise it returns `None`.

This turns `Future<T>` into `Option<T>`.

#### Example

lua

    local fut = Future.new(5)
    assert(fut:now() == Option.Some(5))

### Future:await

lua

    function Future:await() -> T

Waits for the future to finish and returns the value. If the future is already finished, it returns the value immediately.

#### Example

lua

    local fut = Future.new(5)
    assert(fut:await() == 5)

### Future:after

lua

    function Future:after(f: (T) -> ()) -> ()

Calls the given function with the value of the future once it is finished. If the future is already finished, the function is called immediately.

#### Example

lua

    local fut = Future.new(5)
    fut:after(function(value)
      print(value)
    end)


# threadpool

`threadpool` provides a `spawn` function that allows you to run a function in a separate thread like `task.spawn`, however, it will pool and reuse threads.

This uses a global pool of free threads, when `spawn` is called, it'll take a thread from the pool and run the function in it, if there isn't a thread available it'll create a new one. Once the function has finished running, the thread will be returned to the pool.

This can make spawning threads significantly faster than using `task.spawn`.

## Installation

Learn more about [installation](https://lukadev-0.github.io/util.luau/docs/getting-started#installation).

wallypesde

toml

    [dependencies]
    threadpool = "lukadev-0/threadpool@1.0.2"

sh

    pesde add lukadev_0/threadpool@1.0.2

## Functions

### threadpool.spawn

lua

    function threadpool.spawn<T...>(f: (T...) -> (), ...: T...): ()

Executes the given function in a separate thread, with thread pooling.


# std

[View Source](https://github.com/lukadev-0/util.luau/blob/main/packages/std/init.luau)

Runtime agnostic access to standard libraries.

See [supported runtimes](https://lukadev-0.github.io/util.luau/docs/supported-runtimes) for more information.

## Installation

Learn more about [installation](https://lukadev-0.github.io/util.luau/docs/getting-started#installation).

wallypesde

toml

    [dependencies]
    std = "lukadev-0/std@1.0.2"

sh

    pesde add lukadev_0/std@1.0.2

## Libraries

### std.task

lua

    export type TaskLib = {
        cancel: (thread) -> (),
        defer: <T...>(functionOrThread: thread | (T...) -> (), T...) -> thread,
        delay: <T...>(duration: number, functionOrThread: thread | (T...) -> (), T...) -> thread,
        spawn: <T...>(functionOrThread: thread | (T...) -> (), T...) -> thread,
        wait: (duration: number) -> number,

## Types

### std.Runtime

lua

    export type Runtime = {
        name: string,
        libs: {
            task: libs.TaskLib,
        },

### std.RuntimeDefinition

lua

    export type RuntimeDefinition = {
        name: string,
        libs: {
            task: {
                cancel: ((thread) -> ())?,
                defer: (<T...>(functionOrThread: thread | (T...) -> (), T...) -> thread)?,
                delay: (<T...>(duration: number, functionOrThread: thread | (T...) -> (), T...) -> thread)?,
                spawn: (<T...>(functionOrThread: thread | (T...) -> (), T...) -> thread)?,
                wait: ((duration: number) -> number)?,
            }?,
        },

## Properties

### std.runtime

The current runtime, `nil` if running in an unsupported runtime and no runtime has been set.

lua

    std.runtime: Runtime?

## Functions

### std.setRuntime

Sets the current runtime.

lua

    function std.setRuntime(runtime: Runtime): ()

### std.defineRuntime

Defines a runtime.

lua

    function std.defineRuntime(definition: RuntimeDefinition): Runtime


# timer

`timer` allows you to schedule code to run at a future time or at an interval.

## Installation

Learn more about [installation](https://lukadev-0.github.io/util.luau/docs/getting-started#installation).

wallypesde

toml

    [dependencies]
    timer = "lukadev-0/timer@1.0.2"

sh

    pesde add lukadev_0/timer@1.0.2

## Functions

### timer.delay

lua

    function timer.delay(duration: number): Future<number>

Returns a future that resolves after the given duration in seconds, returning the amount of time it took to resolve.

This is equivalent to the following code:

lua

    local fut = Future.spawn(task.wait, duration)

### timer.interval

lua

    function timer.interval(duration: number, callback: function): () -> ()

Calls the given callback every `duration` seconds.

This will correct for drift, it repeatedly calls `task.wait` and calculates the amount of time until the next call.

Returns a function that will stop the interval when called.


# Typechecking

util.luau tries to be as type-safe as possible, so you can catch bugs sooner and get better autocomplete. However due to limitations in Luau, some areas don't typecheck as well as others.

## Callbacks in Methods

When calling a method that takes a callback, such as [`Option:map`](https://lukadev-0.github.io/util.luau/reference/option#option-map) using `:` syntax, the parameters of the callback are not inferred, and instead show up as `a`.

lua

    local opt = Option.Some(4)

    local mapped = opt:map(function(value)
      -- ┌────────────────────────── ^^^^^
      -- └ this is typed as `a` instead of `number`
      return value * 2
    end)

To work around this, you can explicitly type the parameter:

lua

    local opt = Option.Some(4)

    local mapped = opt:map(function(value: number)
      return value * 2
    end)

`value` now has the correct type of `number`. If the type of `value` is incorrect, Luau will throw a type error as it does know the correct type of the function, however it fails to infer it.

lua

    local opt = Option.Some(4)

    -- TypeError: Type
    --   '(string) -> number'
    -- could not be converted into
    --   '(number) -> number'
    local mapped = opt:map(function(value: string)
      return value * 2
    end)

There is an open issue regarding this, [#1011](https://github.com/luau-lang/luau/issues/1011).

Another workaround is to use the `.` syntax instead of `:` syntax:

lua

    local opt = Option.Some(4)

    local mapped = Option.map(opt, function(value)
      -- ┌───────────────────────────────── ^^^^^
      -- └ correctly typed as `number`
      return value * 2
    end)

    -- the following is equivalent
    local mapped = opt.map(opt, function(value)
      return value * 2
    end)

## Type packs

Due to the fact that unions with type packs in them are not supported, types like `Option` or `Future` only take a single type parameter. This means that they can't store tuples.


# Optional Values

The [`option`](https://lukadev-0.github.io/util.luau/reference/option) utility can be used to represent values that may or may not exist, akin to using `nil` to represent values that do not exist.

However, using `nil` to represent non-existing values can be error-prone, and be harder to work with. The `option` utility provides a simpler and safer way to work with optional values.

## Creating options

An option can be in two states: `Some` or `None`. The `Some` state represents a value that exists, and the `None` state represents a value that does not exist.

To create a `Some` option, we can use `Option.Some`:

lua

    local opt = Option.Some(5)

An option can contain multiple values:

lua

    local opt = Option.Some(5, "hello", true)

To create a `None` option, we can use `Option.None`:

lua

    local opt = Option.None

## Accessing the inner values

There are multiple ways to access the inner values of an option.

The easiest way is to use the `unwrap` method, which will return the inner values if it exist, or throw an error if it does not:

lua

    local some = Option.Some(5)
    print(some:unwrap()) -- 5

    local none = Option.None
    none:unwrap() -- throws "called `Option.unwrap()` on a `None` value"

If you need to pass a custom error message, you can use the `expect` method:

lua

    local none = Option.None
    print(none:expect("expected a value")) -- throws "expected a value"

Sometimes, you want to get the inner value but use a default value if it does not exist. You can use the `unwrapOr` method for this:

lua

    local some = Option.Some(5)
    print(some:unwrapOr(10)) -- 5

    local none = Option.None
    print(none:unwrapOr(10)) -- 10

The value passed to `unwrapOr` is eagerly evaluated, so it will be evaluated even if the option is `Some`. If you need to lazily evaluate the default value, you can use the `unwrapOrElse` method:

lua

    local some = Option.Some(5)
    print(some:unwrapOrElse(function()
      return 10
    end)) -- 5

However, there are some cases where you don't want to throw an error or use a default value, but instead want to perform different actions based on whether the option is `Some` or `None`. You can use the `match` method for this:

lua

    local some = Option.Some(5)

    some:match({
      Some = function(value)
        print("got a value:", value)
      end,
      None = function()
        print("got no value")
      end,
    })

Options require you to think about the case where the value does not exist, which can help you write more robust code.

## Transforming options

Aside from accessing the inner value, you can also apply transformations to options and return new options.

You can transform the inner value of an option using the `map` method:

lua

    local some = Option.Some(5)

    local doubled = some:map(function(value)
      return value * 2
    end)

The `Some` value will be doubles, and the `None` will be preserved.

You can also use the `andThen` method to transform the inner value of an option and return a new option:

lua

    local some = Option.Some(5)

    local doubled = some:andThen(function(value)
      if value % 2 == 0 then
        return Option.Some(value * 2)
      else
        return Option.None
      end
    end)

If the `Some` value is even, it will be doubled. Otherwise, `None` will be returned. If the option is `None`, it will be preserved.

You can also use the `match` method from earlier by returning a value from the callbacks:

lua

    local some = Option.Some(5)

    local result = some:match({
      Some = function(value)
        return value * 2
      end,
      None = function()
        return 0
      end,
    })

    print(result) -- 10

You can also filter the inner value of an option using the `filter` method:

lua

    local some = Option.Some(5)

    local even = some:filter(function(value)
      return value % 2 == 0
    end)

The value will be preserved if the option is `Some` and the value is even, and the `None` state will be returned if the option is `None` or the value is odd.

TYPECHECKING

Luau fails to infer function parameters when passing functions to methods when calling them using `:` syntax. [Learn more](https://lukadev-0.github.io/util.luau/reference/option#typechecking).

## Joining options

Sometimes you have multiple options and you want to combine them into a single option.

For example, lets say you had two options, and you wanted to get the sum of their values. You may achieve this using the `andThen` and `map` methods:

lua

    local optA = Option.Some(5)
    local optB = Option.Some(10)

    local sum = optA:andThen(function(a)
      return optB:map(function(b)
        return a + b
      end)
    end)

    print(sum) -- Option::Some(15)

However, this introduces multiple levels of nesting, which may be undesirable.

Instead, we can use the `join` method to turn both options into a single option, which we can map over:

lua

    local optA = Option.Some(5)
    local optB = Option.Some(10)

    local sum = optA:join(optB):map(function(a, b)
      return a + b
    end)

If either option is `None`, the result will be `None`.

## Learn more

There are more methods available on the `Option` type, this was just a small tour of what you can do with options. If you want to learn more, see the [reference](https://lukadev-0.github.io/util.luau/reference/option) for more information.


# Async with Futures

The [`future`](https://lukadev-0.github.io/util.luau/reference/future) utility can be used to represent asynchronous computations.

A future represents a value that does not exist yet, but will exist at some point in the future.

They're useful to represent asynchronous computation such as network requests.

## Creating futures

A future can be in two states: `Pending` or `Finished`. The `Pending` state represents a computation that is still running, and the `Finished` state represents a computation that has finished.

When a future finishes, that is also known as "resolving".

To create a future that is already finished, we can use `Future.new`:

lua

    local fut = Future.new(5)

To create a future that is pending, and will never resolve, you can use `Future.never`:

lua

    local fut = Future.never()

Though, we want our futures to do something, to do this, we can use `Future.spawn` which will spawn a new thread and run the given function:

lua

    local function httpGet(url)
      -- some code to make a network request
    end

    local fut = Future.spawn(httpGet, "https://google.com/")

This future will resolve with the result of the `httpGet` function.

You may also pass an anonymous function to `Future.spawn`:

lua

    local fut = Future.spawn(function()
      return 5
    end)

We can return futures from functions to represent asynchronous computations:

lua

    function httpGet(url: string): Future.Future<string>
      return Future.spawn(function()
        -- some code to make a network request
      end)
    end

MEMORY USAGE

The above code will create a closure for each call to `httpGet`, which may cause high memory usage. To avoid this, you can pass any values the function needs as arguments:

lua

    function httpGet(url: string): Future.Future<string>
      return Future.spawn(function(url)
        -- some code to make a network request
      end, url)
    end

    -- you may also define the function separately if you prefer:

    local function httpGet(url: string): Future.Future<string>
      local function inner(url: string): string
        -- some code to make a network request
      end

      return Future.spawn(inner, url)
    end

This will allow Luau to [cache the function](https://luau-lang.org/performance#closure-caching) and reuse it across calls, reducing memory usage.

## Accessing the inner value

We now have futures that will resolve at some point, but how do we access the inner value?

One way is the `now` method, which will return an [option](https://lukadev-0.github.io/util.luau/docs/optional-values) containing the current value, or `None` if the future is still pending:

lua

    local fut = Future.new(5)

    local value = fut:now():unwrap()
    print(value) -- 5

However, usually we want to wait for the future to resolve, and then do something with the value. We can use the `await` method for this:

lua

    local fut = Future.spawn(httpGet, "https://google.com/")

    local value = fut:await()
    print(value) -- 5

This will yield the current thread until the future resolves, and then return the value.

You may also use the `after` method to execute a callback when the future resolves:

lua

    local fut = Future.spawn(httpGet, "https://google.com/")

    fut:after(function(value)
      print(value) -- 5
    end)

The callback is executed in a separate thread when the future resolves.

## Composing futures

The future utility provides a few methods to compose futures.

The `all` function can be used to wait for every future in an array to resolve:

lua

    local fut1 = Future.new(5)
    local fut2 = Future.new(10)

    local fut = Future.all({ fut1, fut2 })

    local values = fut:await()
    print(values[1]) -- 5
    print(values[2]) -- 10

This will wait for all given futures to resolve, and resolves to an array of the resolved values.

The `race` utility can be used to wait for the first future in an array to resolve:

lua

    local fut1 = Future.new(5)
    local fut2 = Future.new(10)

    local fut = Future.race({ fut1, fut2 })

    local value = fut:await()
    print(value) -- 5

This will wait for the first future to resolve, and resolves to the value of the first resolved future.

## Error handling

Futures do not support throwing errors, to handle errors, you can use futures in combination with [results](https://lukadev-0.github.io/util.luau/docs/error-handling).

For example, the following code will call a yielding function that may fail and wraps it in a future and result:

lua

    local fut = Future.spawn(Result.try, httpGet, "https://google.com/")

You can then await the future and handle the result:

lua

    local res = fut:await()

    res:match({
      Ok = function(value)
        print("Got a response:", value)
      end,
      Err = function(err)
        warn("Failed to do the request:", err)
      end
    })

## Learn more

There are more methods available on the `Future` type, this was just a small tour of what you can do with futures. If you want to learn more, see the [reference](https://lukadev-0.github.io/util.luau/reference/future) for more information.


# Error Handling

The [`result`](https://lukadev-0.github.io/util.luau/reference/result) utility can be used for more robust error handling.

Errors are represented as values instead of being thrown using `error()`, this makes it clear that a function can fail, so you don't forget to handle a potential error which may lead to unexpected behavior or crashes.

## Creating results

A result can be in two states: `Ok` or `Err`. The `Ok` state represents a successful value, and the `Err` state represents an error value.

To create an `Ok` result, we can use `Result.Ok`:

lua

    local res = Result.Ok(5)

To create an `Err` result, we can use `Result.Err`:

lua

    local res = Result.Err("something went wrong")

You can return a result from a function to indicate that the function can fail:

lua

    function divide(a: number, b: number): Result.Result<number, string>
      if b == 0 then
        return Result.Err("cannot divide by zero")
      end

      return Result.Ok(a / b)
    end

If you need to wrap a function that throws errors with a result, you can use `Result.try`:

lua

    local res = Result.try(function()
      error("something went wrong")
    end)

Any errors thrown within the function will be caught and returned as an `Err`, otherwise the return value will be wrapped in an `Ok`.

## Accessing the inner value

There are multiple ways to access the inner value of a result.

The easiest way is to use `Result.unwrap`:

lua

    local res = Result.Ok(5)
    print(Result.unwrap(res)) -- 5

    local res = Result.Err("something went wrong")
    print(Result.unwrap(res)) -- throws "something went wrong"

If the result is an `Err`, `Result.unwrap` will throw an error.

Most of the time, we want to handle the error case without crashing the program. There are other methods to access the inner value of a result without throwing an error.

You can use `Result.unwrapOr` to get the `Ok` value or a default value in case of an `Err`:

lua

    local res = Result.Ok(5)
    print(Result.unwrapOr(res, 0)) -- 5

    local res = Result.Err("something went wrong")
    print(Result.unwrapOr(res, 0)) -- 0

The default value is eagerly evaluated, so it's always evaluated, even if the result is an `Ok`.

You can use `Result.unwrapOrElse` to get the `Ok` value or compute a default value in case of an `Err`:

lua

    local res = Result.Ok(5)
    print(Result.unwrapOrElse(res, function()
      return 0
    end)) -- 5

However, there are some cases where you don't want to throw an error or use a default value, but instead want to perform different actions based on whether the result is `Ok` or `Err`. You can use the `match` method for this:

lua

    local res = Result.Ok(5)

    Result.match(res, {
      Ok = function(value)
        print("success:", value)
      end,
      Err = function(err)
        print("error:", err)
      end
    })

You can also use the `unpack` method, which returns two values: the `Ok` value or nil, and the `Err` value or nil:

lua

    local res = Result.Ok(5)
    local ok, err = Result.unpack(res)
    print(ok, err) -- 5 nil

This is useful to propagate the error in the function, for example, using the `divide` function from before:

lua

    local function doCalculation(x: number): Result<number, string>
      local res = divide(x, x * x)

      local ok, err = res:unpack()
      if err then
        return Result.Err(err)
      end

      return ok
    end

This function will return the result of `divide` if it's `Ok`, otherwise it will return the error. This is the recommended way to propagate errors.

## Transforming results

You can use the `map` method to transform the inner value of a result:

lua

    local res = Result.Ok(5)
    local doubled = res:map(function(value)
      return value * 2
    end)

This will double the value inside the `Ok` result, or preserve the `Err` value.

You can also map the error instead using the `mapErr` method:

lua

    local some = Result.Err(5)

    local doubled = some:mapErr(function(value)
      return value * 2
    end)

You can also use the `andThen` method to transform the inner value of a result and return a new result:

lua

    local res = Result.Ok(5)
    local doubled = res:andThen(function(value)
      if value % 2 == 0 then
        return Result.Ok(value * 2)
      else
        return Result.Err("value is not even")
      end
    end)

This will double the value inside the `Ok` result if it's even, or return the `Err` value if it's odd. If the result is an `Err`, the `andThen` method will preserve the `Err` value.

You can also use the `match` method from earlier by returning a value from the callbacks:

lua

    local res = Result.Ok(5)
    local doubled = Result.match(res, {
      Ok = function(value)
        return value * 2
      end,
      Err = function(err)
        return 0
      end
    })

## Learn more

There are more methods available on the `Result` type, this was just a small tour of what you can do with results. If you want to learn more, see the [reference](https://lukadev-0.github.io/util.luau/reference/result) for more information.


# Supported Runtimes

util.luau is designed to run on any Luau runtime, with out-of-the-box support for Roblox and Lune.

However, some packages require the use of standard libraries that differ between runtimes. For example, [`timer`](https://lukadev-0.github.io/util.luau/reference/timer) requires access to functions to schedule code to run at a later time, this functionality is provided by the `task` global on Roblox, and the `@lune/task` builtin on Lune.

In order to support all of these runtimes, util.luau provides the [`std`](https://lukadev-0.github.io/util.luau/reference/std) package. This package provides common interfaces for standard libraries, and default implementations for supported runtimes.

Currently, the following runtimes are supported out-of-the-box:

  * [Roblox](https://create.roblox.com/docs/reference/engine)
  * [Lune](https://lune-org.github.io/docs)

## Runtime Detection

In order to use the correct library implementations for the current runtime, `std` will automatically try to detect the current runtime, this is done using the following rules:

  * if `_G.UTIL_TARGET` is set to `roblox`, then the Roblox implementations are used. This global is injected for Roblox builds meaning that runtime detection is skipped.
  * if `typeof(script) == "Instance"` is true, then the Roblox implementations are used
  * if `_VERSION` starts with the string `"lune "`, case-insensitive, then the Lune implementations are used.
  * otherwise, the runtime is unknown, and no libraries are implemented.

## Defining Runtimes

If you need to use util.luau in a runtime that is not supported out-of-the-box, You need to define the runtime yourself and implement the standard libraries.

This is done using the [`std.defineRuntime`](https://lukadev-0.github.io/util.luau/reference/std#std-defineruntime) function.

lua

    local std = require(...)

    local myRuntime = std.defineRuntime({
      name = "my-runtime",
      libs = {
        task = {
          cancel = ...,
          defer = ...,
          delay = ...,
          spawn = ...,
          wait = ...,
        },
      },
    })

Not every function needs to be implemented, however an error will be thrown if you try to use a function that is not implemented.

## Using Runtimes

Once you've defined a runtime, you can use it by calling [`std.setRuntime`](https://lukadev-0.github.io/util.luau/reference/std#std-setruntime).

lua

    std.setRuntime(myRuntime)

WARNING

It is important to call this function **_before_ ** any code that uses the standard libraries, otherwise you will get errors.

## Using the Standard Libraries

If you'd like to use the standard libraries, you can do so by requiring the [`std`](https://lukadev-0.github.io/util.luau/reference/std) module and accessing the libraries.

lua

    local std = require(...)

    std.task.spawn(...)

You may also alias the standard libraries to a shorter name if you prefer.

lua

    local task = std.task

However, do not alias functions directly, as this will break the runtime setting functionality if the runtime is set after your module code is ran.

lua

    -- do not do this
    local spawn = std.task.spawn

INFO

It is recommended to use one of the other utilities that wrap the standard libraries, such as [`threadpool`](https://lukadev-0.github.io/util.luau/reference/threadpool) or [`timer`](https://lukadev-0.github.io/util.luau/reference/timer), as these provide a more ergonomic API.


# Fatality
Fatality.Win UI for Roblox - Dark Theme

![image](https://github.com/user-attachments/assets/f1023175-a33b-44fc-8a24-636103e8324e)

# Usage
- [Document](https://cat-sus.gitbook.io/fatality)
- [Example](https://github.com/4lpaca-pin/Fatality/blob/main/example.luau)


fatality.win UI for Roblox

🔌 Installation

Copy

    local Fatality = loadstring(game:HttpGet("https://raw.githubusercontent.com/4lpaca-pin/Fatality/refs/heads/main/src/source.luau"))();

[GitHub - 4lpaca-pin/Fatality: Fatality.win UI for Roblox - Dark ThemeGitHub](https://github.com/4lpaca-pin/Fatality)

Github Page

[NextDocument](https://cat-sus.gitbook.io/fatality/document)

Last updated 9 months ago


Copy

    local Fatality = loadstring(game:HttpGet("https://raw.githubusercontent.com/4lpaca-pin/Fatality/refs/heads/main/src/source.luau"))();
    local Notification = Fatality:CreateNotifier();

    Fatality:Loader({
        Name = "FATALITY",
        Duration = 4
    });

    Notification:Notify({
        Title = "FATALITY",
        Content = "Hello, "..game.Players.LocalPlayer.DisplayName..' Welcome back!',
        Icon = "clipboard"
    })

    local Window = Fatality.new({
        Name = "FATALITY",
        Expire = "never",
    });

    local Rage = Window:AddMenu({
        Name = "RAGE",
        Icon = "skull"
    })

    local Legit = Window:AddMenu({
        Name = "LEGIT",
        Icon = "target"
    })

    local Visual = Window:AddMenu({
        Name = "VISUAL",
        Icon = "eye"
    })

    local Misc = Window:AddMenu({
        Name = "MISC",
        Icon = "settings"
    })

    local Skins = Window:AddMenu({
        Name = "SKINS",
        Icon = "palette"
    })

    local Lua = Window:AddMenu({
        Name = "LUA",
        Icon = "code"
    })

    do
        local Weapon = Rage:AddSection({
            Position = 'left',
            Name = "WEAPON"
        });

        local Extra = Rage:AddSection({
            Position = 'center',
            Name = "EXTREA"
        });

        local General = Rage:AddSection({
            Position = 'right',
            Name = "GENERAL"
        });

        Weapon:AddSlider({
            Name = "Hit-chance",
            Default = 61
        })

        Weapon:AddSlider({
            Name = "Pointscale",
            Type = "%",
            Default = 0
        })

        Weapon:AddSlider({
            Name = "Min-damage",
            Type = "%",
            Default = 85
        })

        Weapon:AddDropdown({
            Name = "Hitboxes",
            Values = {"Head",'Neck','Arms','Legs'}
        })

        Weapon:AddDropdown({
            Name = "Multipoint",
            Values = {"Head",'Neck','Arms','Legs'}
        })

        Weapon:AddDropdown({
            Name = "Target selection",
            Values = {"Damage"},
            Default = "Damage"
        })

        local Autostop = Extra:AddToggle({
            Name = "Autostop",
            Option = true;
        });

        Autostop.Option:AddToggle({
            Name = "Something"
        })

        Autostop.Option:AddToggle({
            Name = "Something"
        })

        Autostop.Option:AddToggle({
            Name = "Something"
        })

        Autostop.Option:AddToggle({
            Name = "Something"
        })

        Extra:AddToggle({
            Name = "Autoscope",
        });

        Extra:AddToggle({
            Name = "Ignore limbs on moving",
        });

        Extra:AddToggle({
            Name = "Autorevolver",
        });

        General:AddToggle({
            Name = "Aimbot",
            Risky = true
        })

        General:AddToggle({
            Name = "Slient aim",
            Risky = false
        })

        General:AddSlider({
            Name = "Maximum fov",
            Type = " deg",
            Default = 0
        })

        General:AddToggle({
            Name = "Autofire",
            Risky = false
        })

        General:AddToggle({
            Name = "Delay shot",
            Risky = false
        })

        General:AddToggle({
            Name = "Duck peek assist",
            Risky = false
        })

        General:AddToggle({
            Name = "Force bodyaim",
            Risky = false
        })

        General:AddToggle({
            Name = "Force shoot",
            Risky = false
        })

        General:AddToggle({
            Name = "Headshot only",
            Risky = false
        })

        General:AddToggle({
            Name = "Knife bot",
            Risky = false
        })

        General:AddToggle({
            Name = "Zeus bot",
            Risky = false
        })

        local NoSpread = General:AddToggle({
            Name = "Nospread",
            Risky = false,
            Option = true
        })

        NoSpread.Option:AddToggle({
            Name = "Something"
        })

        NoSpread.Option:AddToggle({
            Name = "Something"
        })

        NoSpread.Option:AddToggle({
            Name = "Something"
        })

        NoSpread.Option:AddToggle({
            Name = "Something"
        })

        local Doubletap = General:AddToggle({
            Name = "Doubletap",
            Risky = true,
            Option = true
        })

        Doubletap.Option:AddToggle({
            Name = "Something"
        })

        Doubletap.Option:AddToggle({
            Name = "Something"
        })

        Doubletap.Option:AddToggle({
            Name = "Something"
        })

        Doubletap.Option:AddToggle({
            Name = "Something"
        })

        General:AddButton({
            Name = "Notification",
            Callback = function()
                Notification:Notify({
                    Title = "Notification",
                    Content = "Testing Notification",
                    Duration = math.random(3,7),
                    Icon = "info"
                })
            end,
        })
    end

    do
        local Aim = Legit:AddSection({
            Position = 'left',
            Name = "AIM"
        });

        local Rcs = Legit:AddSection({
            Position = 'left',
            Name = "RCS"
        });

        local Trigger = Legit:AddSection({
            Position = 'center',
            Name = "TRIGGER"
        });

        local Backtrack = Legit:AddSection({
            Position = 'center',
            Name = "BACKTRACK"
        });

        local General = Legit:AddSection({
            Position = 'right',
            Name = "GENERAL"
        });

        Aim:AddToggle({
            Name = "Aim assist"
        })

        Aim:AddDropdown({
            Name = "Mode",
            Default = "Adaptive",
            Values = {"Adaptive","value 1",'Value 2'}
        })

        Aim:AddDropdown({
            Name = "Hitboxes",
            Multi = true,
            Default = {
                ["Head"] = true
            },
            Values = {
                "Head",
                'Neck',
                'Arms',
                'Legs'
        })

        Aim:AddSlider({
            Name = "Multipoint"
        })

        Aim:AddSlider({
            Name = "Aim fov",
            Round = 1,
            Default = 0.1,
            Type = " deg"
        })

        Aim:AddSlider({
            Name = "Aim speed",
            Default = 1,
            Type = "%"
        })

        Aim:AddSlider({
            Name = "Min-damage",
            Default = 61,
        })

        Aim:AddToggle({
            Name = "Only in scpoe"
        })

        Aim:AddToggle({
            Name = "Autostop"
        })

        Rcs:AddToggle({
            Name = "Recoil control"
        })

        Rcs:AddSlider({
            Name = "Speed",
            Default = 1,
            Type = "%"
        })

        Rcs:AddToggle({
            Name = "Re-center"
        })

        Rcs:AddSlider({
            Name = "Start bullet",
            Default = 1,
        })

        Trigger:AddToggle({
            Name = "Triggerbot"
        })

        Trigger:AddSlider({
            Name = "Hit-chance",
            Default = 100,
            Type = "%"
        })

        Trigger:AddToggle({
            Name = "Use seed when available"
        })

        Trigger:AddSlider({
            Name = "Min-damage",
            Default = 0,
            Type = "%"
        })

        Trigger:AddSlider({
            Name = "Reaction time",
            Default = 0,
            Type = "ms"
        })

        Trigger:AddToggle({
            Name = "Wait for aim assist hitgroup"
        })

        Trigger:AddToggle({
            Name = "Only in Scope"
        })

        Backtrack:AddSlider({
            Name = "Backtrack",
            Default = 0,
            Type = "%"
        })

        General:AddToggle({
            Name = "Enabled"
        })

        General:AddDropdown({
            Name = "Disablers",
            Values = {"d1",'d2'}
        })

        General:AddToggle({
            Name = "Visualize fov",
            Option = true
        }).Option:AddColorPicker({
            Name = "Color",
            Default = Color3.fromRGB(255, 34, 75)
        })

        General:AddToggle({
            Name = "Autorevolver"
        })
    end

    do
        local Misc = Visual:AddSection({
            Name = "MISC",
            Position = 'left'
        })

        local Model = Visual:AddSection({
            Name = "MODEL",
            Position = 'center'
        })

        Misc:AddToggle({
            Name = "Thirdperson",
            Option = true
        }).Option:AddSlider({
            Name = "Distance"
        });

        Misc:AddToggle({
            Name = "Overhead override",
            Option = true
        }).Option:AddDropdown({
            Name = "Override"
        });

        Misc:AddToggle({
            Name = "Fov override",
            Option = true
        }).Option:AddToggle({
            Name = "Something"
        })

        Misc:AddToggle({
            Name = "Viewmodel override",
            Option = true
        }).Option:AddToggle({
            Name = "Something"
        })

        Misc:AddDropdown({
            Name = "Remove scope"
        })

        local pc = Misc:AddToggle({
            Name = "Penetration crosshair",
            Option = true
        }).Option;

        pc:AddColorPicker({
            Name = "Walls",
            Default = Color3.fromRGB(111, 255, 0)
        })

        pc:AddColorPicker({
            Name = "Can't walls",
            Default = Color3.fromRGB(255, 0, 4)
        })

        Misc:AddToggle({
            Name = "Force crosshair",
            Option = true
        }).Option:AddToggle({
            Name = "Something"
        })

        Misc:AddDropdown({
            Name = "Spread"
        })

        Misc:AddToggle({
            Name = "Bullet tracer",
            Option = true
        }).Option:AddColorPicker({
            Name = "Color",
            Default = Color3.fromRGB(255, 41, 116)
        })

        Model:AddDropdown({
            Name = "Visible",
            Default = "Disabled",
            Values = {"Disabled",'Something'}
        })

        Model:AddDropdown({
            Name = "Invisible",
            Default = "Disabled",
            Values = {"Disabled",'Something'}
        })

        Model:AddDropdown({
            Name = "Arms",
            Default = "Disabled",
            Values = {"Disabled",'Something'}
        })

        Model:AddDropdown({
            Name = "Viewmodel",
            Default = "Disabled",
            Values = {"Disabled",'Something'}
        })

        Model:AddDropdown({
            Name = "Attachments",
            Default = "Disabled",
            Values = {"Disabled",'Something'}
        })

        Model:AddToggle({
            Name = 'Glow',
            Option = true

        }).Option:AddColorPicker({
            Name = "Color"
        })

        Model:AddKeybind({
            Name = "Toggle"
        })

    end

[PreviousDocument](https://cat-sus.gitbook.io/fatality/document)

Last updated 9 months ago


Preview

Installation

Copy

    local Fatality = loadstring(game:HttpGet("https://raw.githubusercontent.com/4lpaca-pin/Fatality/refs/heads/main/src/source.luau"))();

Creating Notification

Creating Window

Creating Menu

Creating Section

Creating Toggle

What's Option?

Option Preview

Creating Slider

Creating Button

Creating Color Picker

Creating Dropdown

Creating Multi Dropdown

Creating Keybind

Loader

loading animation

[PreviousFatality](https://cat-sus.gitbook.io/fatality)[NextExample](https://cat-sus.gitbook.io/fatality/example)

Last updated 9 months ago


🖍 Rich Text styling done right

## Guide
>[Highlights](#Highlights)
>[Install](#Install)
>[Usage](#Usage)
>[API](#API)
>[Styles](#Styles)
>[Comments](#Comments)
>[Maintainers](#Maintainers)

## Highlights
- Expressive API
- Highly performant
- No dependencies
- Ability to nest styles
- Auto-detects color support
- Clean and focused
- Actively maintained
- Extremely Lightweight (less than ~270 lines)
- Proper Typing for AutoFill

## Install

**Roblox Console**
```lua
-- Run in Roblox Studio Console
local HttpService = game:GetService("HttpService");
local ReplicatedStorage = game:GetService("ReplicatedStorage");
local LastValue = HttpService.HttpEnabled

HttpService.HttpEnabled = true

local ChalkModule = Instance.new("ModuleScript");
ChalkModule.Name = "Chalk";
ChalkModule.Parent = ReplicatedStorage;

local Request = HttpService:RequestAsync({
    Url = "https://raw.githubusercontent.com/Perthys/chalk/refs/heads/main/src/main.luau";
    Method = "GET";
});

HttpService.HttpEnabled = LastValue

if Request.Success and Request.StatusCode == 200 then
    ChalkModule.Source = Request.Body

    print("Successfully installed Chalk module. At:", ChalkModule);
else
    ChalkModule:Destroy()
    error("Failed to install Chalk module.");
end

**Wally**
```toml
[dependencies]
chalk = "perthys/chalk@1.0.3"

## Usage

**Blue Text Example**
> Chalk has a very simple but powerful API

```lua
local ReplicatedStorage = game:GetService("ReplicatedStorage");
local Chalk = require(ReplicatedStorage:WaitForChild("Chalk"));

local TextBox = script.Parent;

TextBox.Text = Chalk.blue('Hello world!')

**Multi String Example**
> Chalk comes with an easy to use composable API where you just chain and nest the styles you want.

```lua
local ReplicatedStorage = game:GetService("ReplicatedStorage");
local Chalk = require(ReplicatedStorage:WaitForChild("Chalk"));

local TextBox = script.Parent; TextBox.RichText = true;

local function Update(String) TextBox.Text = String; task.wait(1); end

Update(Chalk.blue("Hello") .. 'World' .. Chalk.red("!"))
Update(Chalk.blue.bold("Hello world!"))
Update(Chalk.blue("Hello", "World!", "Foo", "bar", "biz", "baz"))
Update(Chalk.red("Hello", Chalk.underline("world") .. "!"))
Update(Chalk.green("I am a green line " .. Chalk.blue.underline.bold("with a blue substring") .. " that becomes green again!"))

Update(("CPU: %s \nRAM: %s \nDISK: %s"):format(Chalk.red("90%"), Chalk.green("40%"), Chalk.yellow("70%")))

Update(Chalk.color(123, 45, 67).underline("Underlined reddish color"))
Update(Chalk.color("#DEADED").bold("Bold gray!"))

**Theme Creation**
> Easily define your own themes

```lua
local ReplicatedStorage = game:GetService("ReplicatedStorage");
local Chalk = require(ReplicatedStorage:WaitForChild("Chalk"));

local TextBox = script.Parent; TextBox.RichText = true;

local error = Chalk.bold.red;
local warning = Chalk.color("#FFA500");

local function Update(String) TextBox.Text = String; task.wait(1); end

Update(error("Error!"))
Update(warning("Warning!"));

Take advantage of string substitution:

```lua
local ReplicatedStorage = game:GetService("ReplicatedStorage");
local Chalk = require(ReplicatedStorage:WaitForChild("Chalk"));

local TextBox = script.Parent; TextBox.RichText = true;

local function Update(String) TextBox.Text = String; task.wait(1); end

local Name = "Builderman";
Update(Chalk.green(("Hello %s"):format(Name)))

## API

### Chalk Syntax and Typing

**Example:**
```lua
chalk[ ArgumentStyle ] -> (...: StyleArgs) -> chalk(...: string)
chalk.size(40)("test");

chalk[ ModifierStyle ] -> chalk(...: string)
chalk.bold("test");

chalk[ ArgumentStyle ] -> (...: StyleArgs) -> chalk[ ArgumentStyle ] -> (...) -> chalk(...: string)
chalk.size(40).color(40,20,30)("test");

chalk[ ArgumentStyle ] -> (...: StyleArgs) -> chalk[ ModifierStyle ] -> chalk(...: string)
chalk.size(40).bold("test");

chalk[ ModifierStyle ] -> chalk[ ModifierStyle ] -> chalk(...: string)
chalk.red.bold("test");

chalk[ ModifierStyle ] -> chalk[ ArgumentStyle ] -> (...: StyleArgs) -> chalk(...: string)
chalk.red.size(40)("test");

Chain [styles](#styles) calls the last Style as a method with a string argument.
Order doesn't matter, and earlier Styles take priority in case of a conflict.
This simply means that `chalk.red.yellow.green` is equivalent to `chalk.red`.

## Styles

### Modifier Styles
- `Chalk.bold` - Make the text bold
- `Chalk.italic` - Make the text italic
- `Chalk.underline` - Underline the text
- `Chalk.strikethrough` - Strike through the text
- `Chalk.uppercase` - Convert text to uppercase
- `Chalk.smallcaps` - Convert text to small capitals

### Argument Modifier Style
- `Chalk.color(Hex) | Chalk.color(R, G, B) | Chalk.color(Color3.new())` - Set the color
- `Chalk.size([<Size>])` - Set the size of the text (Number)
- `Chalk.face([<Face>])` - Set the typeface of the text (String)
- `Chalk.family([<rbxasset://>])` - Set the font family from an asset (String)
- `Chalk.weight([<Weight>])` - Set the font weight (String)
- `Chalk.transparency([])` - Set the transparency of the text (Number 0-1)
- `Chalk.stroke({Color = [<Color>], Joins = [<Joins>], Thickness = [], Transparency = []})` - Define stroke properties: color (Color3), joins (String), thickness (Number), and transparency (Number)

```lua
Chalk.stroke({
    Color = [<Color>],
    Joins = [<Joins>],
    Thickness = [],
    Transparency = []
})

### Example Game
[`ExampleGame`](https://github.com/Perthys/chalk/raw/main/ExampleGame.rbxl)

### Colors

- `Chalk[]` - Set the color to a BrickColor [`Colors`](https://create.roblox.com/docs/reference/engine/datatypes/BrickColor#r)
- `Chalk.white` - Set the color to white
- `Chalk.black` - Set the color to black
- `Chalk.red` - Set the color to red
- `Chalk.brown` - Set the color to brown
- `Chalk.orange` - Set the color to orange
- `Chalk.yellow` - Set the color to yellow
- `Chalk.lime` - Set the color to lime
- `Chalk.green` - Set the color to green
- `Chalk.blue` - Set the color to blue
- `Chalk.purple` - Set the color to purple
- `Chalk.pink` - Set the color to pink

## Color3, 256 RGB, Hex and BrickColor support

Chalk supports Color3, 256 RGB, Hex and BrickColor.

Examples:

- `Chalk.color('#DEADED').underline('Hello, world!')`
- `Chalk.color(15, 100, 204)`
- `Chalk.color(Color3.fromRGB(100, 255, 255))`
- `Chalk.nougat`

The following color models can be used:

- [`rgb`](https://en.wikipedia.org/wiki/RGB_color_model) - Example: `chalk.color(255, 136, 0).bold('Orange!')`
- [`hex`](https://en.wikipedia.org/wiki/Web_colors#Hex_triplet) - Example: `chalk.color('#FF8800').bold('Orange!')`
- [`Color3`](https://create.roblox.com/docs/reference/engine/datatypes/Color3) - Example: `chalk.color(Color3.fromRGB(255, 136, 0)).bold("Orange")`
- [`BrickColor`](https://create.roblox.com/docs/reference/engine/datatypes/BrickColor) - Example `chalk["Earth orange"]`

## Origin story
I wanted to make the [`npm package`](https://www.npmjs.com/package/chalk) [`chalk`](https://github.com/chalk/chalk) for roblox luau [`richtext`](https://create.roblox.com/docs/ui/rich-text) because I *really* did not want to do styling manually.

## Comments
- ROBLOX PLEASE ENABLE RICH TEXT TO CONSOLE TEXT OBJECTS, you can make a interface with LogService so print/warn/error can still output raw text.
- If roblox adds support for background text color directly with richtext I will also add support.
- If you have any issues or suggestions best way to contact me would be through discord `Perthys#0`.

## Maintainers

- [Perth](https://github.com/Perthys) | `Perthys#0`


# Roblox Studio WakaTime

This is a plugin for automatically tracking your time spent in Roblox Studio, with support for tracking:

-   Time spent in the code editor (with script names)
-   Time spent playtesting
-   Time spent editing in the viewport

## Installation

[Install on the Creator Hub](https://create.roblox.com/store/asset/76658431643665/WakaTime)

It is also possible to place the latest `rbxm` from the [Releases](https://github.com/tacheometry/roblox-studio-wakatime/releases) tab in your local plugins folder.

![Screenshot](./assets/plugin_screenshot.png)

## Building

> [!IMPORTANT]
> Please make sure to install the required [Dependencies](./wally.toml) via the following command:
> wally install

To generate a build for _testing_, run:

rojo build -p "RobloxStudioWakaTime.rbxm"

_This will automatically install it into your **Roblox Studio** Plugins folder._

To manually generate a **final** build, run:

rojo build -o "RobloxStudioWakaTime.rbxm"

_This will instead just generate the file directly in **this** directory._


* [Leaderboards](https://wakatime.com/leaders)
  * [Teams](https://wakatime.com/teams)
  * [Plugins](https://wakatime.com/plugins)
  * [Docs](https://wakatime.com/developers)

  * [Sign Up](https://wakatime.com/signup)
  * [Log In](https://wakatime.com/login)


# CanvasDraw

![CanvasDraw logo (1)-1 png (1)](https://github.com/user-attachments/assets/5fb46068-470a-42e7-a66c-accbb3956d30)

**CanvasDraw** is a fast and powerful graphics library for Roblox utilising EditableImage.

https://github.com/user-attachments/assets/c29668bd-808b-43a3-ae80-c49fa3812ce4

https://github.com/user-attachments/assets/eb8e7dcd-f7a4-4ea5-9608-0db7acb184ed

You can read more about the asset [here!](https://devforum.roblox.com/t/1624633)

Join the discord community server [here!](https://discord.gg/UBewvu3p2c)