Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 17 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ indoc = "1.0.3"
log = "0.4.11"
once_cell = "1.5.2"
opener = "0.5.0"
reqwest = { version = "0.11.18", features = ["blocking", "json"] }
reqwest = { version = "0.11.18", default-features = false, features = ["blocking", "json", "rustls-tls"] }
rpassword = "5.0.1"
semver = { version = "0.11.0", features = ["serde"] }
serde = { version = "1.0.116", features = ["derive"] }
Expand Down
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

* [Installation](#installation)
* [Commands](#commands)
* [Type Re-export Functionality](#type-re-export-functionality)
* [Prior Art](#prior-art)
* [Manifest Format](#manifest-format)
* [Lockfile Format](#lockfile-format)
Expand Down Expand Up @@ -189,6 +190,13 @@ exclude = ["node_modules"]
# Packages can be marked as private to prevent them from being published.
private = true

[place]
# Where the shared packages folder is located in the Roblox Datamodel
shared-packages = "game.ReplicatedStorage.Packages"

# Where the server packages folder is located in the Roblox Datamodel
server-packages = "game.ServerScriptStorage.Packages"

[dependencies]
# Most dependencies will look like this.
#
Expand All @@ -211,6 +219,39 @@ Promise = "evaera/promise@2.0.1"
TestEZ = "roblox/testez@0.4.1"
```

## Type Re-export Functionality

Wally automatically generates type re-exports to improve Luau type checking support in Roblox projects. This runs as a post-pass immediately after installation.

### How it works

- After installation, Wally traverses `Packages`, `ServerPackages`, and `DevPackages` and inspects generated link thunks.
- It resolves the `require(...)` target using the filesystem relative to the thunk location:
- Supports `script.Parent` chains and `game.*.Packages` paths.
- Probes module files in this order: exact path, `{name}.lua` / `{name}.luau`, `init.lua` / `init.luau`, `src/init.lua` / `src/init.luau`.
- It scans the target module textually for lines beginning with `export type` and emits re-exports into the thunk:
- Keeps the original generic parameter list on the left-hand side.
- Uses only generic names (not defaults) on the right-hand side.
- Includes variadic generic packs (e.g., `T...`).

### Example

A simple package thunk like:
```lua
return require(script.Parent.Parent["scope/package"]["package"])
```

Becomes a type-aware thunk like:
```lua
local REQUIRED_MODULE = require(script.Parent.Parent["scope/package"]["package"])

export type MyExportedType = REQUIRED_MODULE.MyExportedType

return REQUIRED_MODULE
```

This enables proper type checking when using Wally packages in your Roblox projects.

## Lockfile Format
The lockfile contains the exact versions of each dependency that a project depends on. They're a critical feature that ensures that everyone who works on a game is getting the exact same version of every package.

Expand Down
6 changes: 3 additions & 3 deletions src/commands/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use structopt::StructOpt;
use crate::installation::InstallationContext;
use crate::lockfile::Lockfile;
use crate::manifest::Manifest;
use crate::package_id::PackageId;
use crate::package_source::{PackageSource, PackageSourceMap, Registry, TestRegistry};
use crate::resolution::resolve;

Expand Down Expand Up @@ -136,12 +135,13 @@ impl InstallSubcommand {
SetForegroundColor(Color::DarkGreen),
SetForegroundColor(Color::Reset)
));
let root_package_id = PackageId::new(manifest.package.name, manifest.package.version);

let root_package_id = manifest.package_id();
let installation = InstallationContext::new(
&self.project_path,
manifest.place.shared_packages,
manifest.place.server_packages,
);
)?;

installation.clean()?;
progress.println(format!(
Expand Down
2 changes: 1 addition & 1 deletion src/commands/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl UpdateSubcommand {
&self.project_path,
manifest.place.shared_packages,
manifest.place.server_packages,
);
)?;

progress.set_message(format!(
"{} Cleaning {}package destination...",
Expand Down
Loading